17

Is there an easy way to replace an entire embedded document in an array? Say replacing:

{
   "_id" : "2",
      "name" : "name2",
      "xyz..." : "xyz2..."
}

with:

{
   "_id" : "2",
      "name" : "name6",
      "xyz..." : "xyz5..."
      "morefields..." : "fields..."
}

Searching for _id (embedded). Or do I need to replace each field individually using $set?

{
  "_id" : "2",
  "users" : [{
      "_id" : "1",
      "name" : "name1",
      "xyz..." : "xyz1..."
    }, {
      "_id" : "2",
      "name" : "name2",
      "xyz..." : "xyz2..."
    }],
  "name" : "main name"
}

1 Answer 1

26

You are using the "array of objects" pattern. You can use the positional operator, it should look something like this:

coll.update( {'_id':'2', 'users._id':'2'}, {$set:{'users.$':{ "_id":2,"name":"name6",... }}}, false, true)

In my experience, the "array of objects" pattern is not optimal if the objects have a natural ID. In your case, this could be modeled as the following:

{
  "_id" : "2",
  "users" : 
    { "1" : { "name" : "name1", "xyz..." : "xyz1..." }, 
      "2" : { "name" : "name2", "xyz..." : "xyz2..." }
    }
  "name" : "main name"
}

In this case you can use the dot notation to easily update the item you want.

var newValue = {  "name" : "name6", "xyz..." : "xyz5...", "morefields..." : "fields..." };
coll.update({_id: 2}, { $set: { "users.2" : newValue } });
Sign up to request clarification or add additional context in comments.

9 Comments

That works great, thanks! Interesting the 2nd alternative but I'm not sure it will work since I'll need to remove some entries in the middle. "users.2" is the position in the array I assume.
I thought users.2 referred to the array position but it's actually using the id (and returning empty brackets for all other array items}, cool.
MongoDB recognizes arrays in a query. So users.2 could search through the users array looking for objects with key of 2 or it could look at the key:2 of users.
I was going with your second model but now I'm thinking I won't be able to index the inner name field. If it was an array it would be users.name but here it's users.1.name users.2.name?
You are correct, the second structure does not index very well. This is definitely a trade-off. But you cannot optimize for all queries with MongoDB. If you want this query to be fast, then you have to trade off ease of updating.
|

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.