Search code examples
mongodbmeteor

Update a subdocument contained in an array contained in a MongoDB document


Documents.update(
  {_id: Session.get("current_document_id")}, 
  {$push: {schema: {type: "text", size: size, name: name, label: label}}}
);

The above query is a Meteor collection, and 'Documents.update' maps to 'db.documents.update' in MongoDB documentation (http://docs.mongodb.org/manual/applications/update/). With that query I can add a schema document inside the main document. Subdocuments are stored in an array:

Document:
  schema:
    array:
      {type: "text", size: 6, name: "first_name", label: "First name"},
      {type: "text", size: 6, name: "last_name", label: "Last name"}

I want to modify the name and size attributes of the subdocuments with this query:

Documents.update(
  {_id: Session.get("current_document_id"), 'schema' : "first_name"}, 
  {$push: {schema: {type: "text", size: 7, name: name, label: "First Name2"}}}
);

But that operation append a new object directly under schema and deletes the array:

Document:
  schema:
      {type: "text", size: 7, name: "first_name", label: "First Name2"}

How can I modify the query to change the attributes avoiding this issue? After the query I would like to have this document:

Document:
  schema:
    array:
      {type: "text", size: 7, name: "first_name", label: "First name2"},
      {type: "text", size: 6, name: "last_name", label: "Last name"}

Solution

  • You can update an existing array element using a $set operation that uses the $ positional operator to identify the array element matched in the selector like this:

    Documents.update(
      {_id: Session.get("current_document_id"), 'schema.name': "first_name"}, 
      {$set: {'schema.$': {type: "text", size: 7, name: name, label: "First Name2"}}}
    );
    

    This will replace the matched schema element with the one included in the $set object.

    If you only want to update individual fields of the targeted schema element, you can use dot notation. For example, to only update the size and name fields:

    Documents.update(
      {_id: Session.get("current_document_id"), 'schema.name': "first_name"}, 
      {$set: {'schema.$.size': 7, 'schema.$.name': name}}
    );