1

I have the following document structure in a MongoDB collection :

{
  "A" : [ {
      "B" : [ { ... } ]
  } ]
}

I'd like to update this to :

{
  "A" : [ {
      "B" : [ { ... } ],
      "x" : [],
      "y" : { ... }
  } ]
}

In other words, I want the "x" and "y" fields to be added to the first element of the "A" array without loosing "B".

2
  • Do you've multiple objects in A array ? To which object do you wanted to push x & y beside B ? Commented Mar 26, 2020 at 1:16
  • @whoami No other objects in array A and x and y will only go into A[0] but they must not overwrite B Commented Mar 26, 2020 at 5:21

2 Answers 2

1

Ok as there is only one object in A array you could simply do as below :

Sample Collection Data :

{
  "_id" : ObjectId("5e7c3cadc16b5679b4aeec26"),
  A:[
     {
       B: [{ abc: 1 }]
     }
    ]
}

Query :

/** Insert new fields into 'A' array's first object by index 0 */
db.collection.updateOne(
    {  "_id" : ObjectId("5e7c3f77c16b5679b4af4caf") },
    { $set: { "A.0.x":  [] , "A.0.y" : {abcInY :1 }} }
  )

Output :

{
    "_id" : ObjectId("5e7c3cadc16b5679b4aeec26"),
    "A" : [ 
        {
            "B" : [ 
                {
                    "abc" : 1
                }
            ],
            "x" : [],
            "y" : {
                "abcInY" : 1.0
            }
        }
    ]
}

Or Using positional operator $ :

db.collection.updateOne(
    { _id: ObjectId("5e7c3cadc16b5679b4aeec26") , 'A': {$exists : true}},
    { $set: { "A.$.x":  [] , "A.$.y" : {abcInY :1 }} }
  )

Note : Result will be the same, but functionally when positional operator is used fields x & y are inserted to first object of A array only when A field exists in that documents, if not this positional query would not insert anything (Optionally you can check A is an array condition as well if needed). But when you do updates using index 0 as like in first query if A doesn't exist in document then update would create an A field which is an object & insert fields inside it (Which might cause data inconsistency across docs with two types of A field) - Check below result of 1st query when A doesn't exists.

{
    "_id" : ObjectId("5e7c3f77c16b5679b4af4caf"),
    "noA" : 1,
    "A" : {
        "0" : {
            "x" : [],
            "y" : {
                "abcInY" : 1.0
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the suggestion, I think your first solution should work. I've added another solution using piplines within update.
0

However, I think I was able to get anothe@whoami Thanks for the suggestion, I think your first solution should work. However, I think I was able to get another solution to this though I'm not sure if its better or worse (performance wise?) than what you have here. My solution is:

db.coll.update( { "_id" : ObjectId("5e7c4eb3a74cce7fd94a3fe7") }, [ { "$addFields" : { "A" : { "x" : [ 1, 2, 3 ], "y" : { "abc" } } } } ] )

The issue with this is that if "A" has more than one array entry then this will update all elements under "A" which is not something I want. Just out of curiosity is there a way of limiting this solution to only the first entry in "A"?

1 Comment

aggregation pipeline in update operations is introduced starting MongoDB v4.2, which is a powerful way to update documents - which is only needed for complex updates where you need to do some operations with existing fields or use MongoDB's operator. And $set is nothing but $addFields in aggregation, if you look query executing in back-end, end of the day it will do the same, For your basic need you need not to use pipeline :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.