Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mongodb aggregation, is it possible to add entries to an array during $project

I have documents of the form:

{
    _id : ObjectId(.....),
    prop1 : "foo",
    links : [ 1, 2, 3, 4 ]
}

{
    _id : ObjectId(.....),
    prop1 : "bar",
    links : [ 5, 6, 7, 8 ]
}

I am using the aggregation framework to process these documents, I use $unwind to generate a document for each value in the links array.

But I have three cases where I need to update the documents before calling $unwind, I have been looking at the $project operation, but I can find no information about how to create or update arrays for the following cases.

1) The links property is missing

{
    _id : ObjectId(.....),
    prop1 : "far"
}

I need to insert the links array

2) The links array property is an empty array

{
    _id : ObjectId(.....),
    prop1 : "far",
    links : []
}

I need to insert a value into the array

3) The links array has too few values

{
    _id : ObjectId(.....),
    prop1 : "far",
    links : [ 9, 10 ]
}

I need to insert additional values into the array

like image 438
user2808819 Avatar asked Dec 11 '13 11:12

user2808819


People also ask

How do I add elements to an array in MongoDB?

If the value is an array, $push appends the whole array as a single element. To add each element of the value separately, use the $each modifier with $push . For an example, see Append a Value to Arrays in Multiple Documents. For a list of modifiers available for $push , see Modifiers.

What does $project do in MongoDB?

The $project takes a document that can specify the inclusion of fields, the suppression of the _id field, the addition of new fields, and the resetting of the values of existing fields. Alternatively, you may specify the exclusion of fields. Specifies the inclusion of a field.

Can we use push in project MongoDB?

Push and Pull are the two operations used to add and remove elements from arrays in MongoDB documents. Pushing and pulling elements are done using the MongoDB $push and $pull operators, respectively: The $push operator appends a specified value to an array.

Which aggregation method is preferred for use by MongoDB?

The pipeline provides efficient data aggregation using native operations within MongoDB, and is the preferred method for data aggregation in MongoDB. The aggregation pipeline can operate on a sharded collection. The aggregation pipeline can use indexes to improve its performance during some of its stages.


1 Answers

You should be able to use $isNull (reference):

db.test.aggregate({ $project : { the_links: { $ifNull : ["$links" , [5,6]]}} })

It's simple logic that if the referenced field ($links) is null, the replacement value (in this case [5, 6]) is used. I renamed the field to the_links in the example.

Assuming the links field is null (and not an empty array). Given data like:

{ "_id" : ObjectId(...), "prop1" : "foo", "links" : [  1,  2,  3,  4 ] }
{ "_id" : ObjectId(...), "prop1" : "bar" }

The aggregation above produces:

{
    "result" : [
            {
                    "_id" : ObjectId("52a869d51d02442354276cff"),
                    "the_links" : [
                            1,
                            2,
                            3,
                            4
                    ]
            },
            {
                    "_id" : ObjectId("52a869e31d02442354276d00"),
                    "the_links" : [
                            5,
                            6
                    ]
            }
    ],
    "ok" : 1
}

If links were an empty array [] rather than null, you could do something like:

db.test.aggregate({ $project : 
     { the_links: { $cond : [ { $eq : ["$links", []]}, '$links', [5,6]]}} })

But, if it's either null or [], then you'd need to add an additional check for that condition as an $or within the $cond operator.

If the list has values, and you want to add more values conditionally, the current (2.4.x) production build of MongoDB does not have an effective solution. The development branch has an operator called $size which will return the length of an array (jira). You could then conditionally add them using yet another development feature called $setUnion:

$setUnion Takes any number of arrays and returns an array that containing the elements that appear in any input array.

like image 198
WiredPrairie Avatar answered Oct 14 '22 03:10

WiredPrairie