简体   繁体   中英

mongodb update push array

I have the following schema. I am using node.js with mongodb

attributes: {
    type: { type: 'string' },
    title: { type:'string' },
    description: { type:'string' },
    is_active: { type:'boolean',defaultsTo:true },
    createdBy: { type:'json' },
    attachments:{ type:'array' }
}

arr = [{
    'id':attResult.id,
    'subtype':type,
    'title'  : attResult.title,
    'body'  : attResult.body,
    'filetype' : attResult.filetype
}];

I am trying to push a attachments into the 'attachments' array that will be unique to the document.

This is the my query.

books.update(
    { id: refid },
    { $push: { attachments: arr } }
).done(function (err, updElem) {
    console.log("updElem" + JSON.stringify(updElem));     
});

What is the problem in my query,no error but not updated attachments.

I want my result to be this:

{ 
    "_id" : 5,
    "attachments": [
        { 
            "id": "xxxxxxx",
            "subtype": "book",
            "title": "xxxx",
            "body": "xxxx" ,
            "filetype" : "xxxxx"
        },
        {
            "id": "xxxxxxx",
            "subtype": "book",
            "title": "xxxx",
            "body": "xxxx",
            "filetype": "xxxxx"
        }
    ]
}

Looking at your question a little bit more I'm betting that you are actually using "sails" here even though your question is not tagged as such.

The issue here is that the waterline ODM/ORM has it's own ideas about what sort of operations are actually supported since it tries to be agnostic between working with SQL/NoSQL backends and sort of demands a certain may of doing things.

The result is that updates with $push are not really supported at present and you need more of a JavaScript manipulation affair. So in fact you need to manipulate this via a .findOne and .save() operation:

books.findOne(refid).exec(function(err,book) {
   book.attachments.push( arr[0] );
   book.save(function(err){
     // something here
   });
});

Part of that is "waterline" shorthand for what would otherwise be considered an interchangeable use of _id and id as terms, where just specifying the id value as a single argument implies that you are referring to the id value in your query selection.

So unless you replace the waterline ODM/ORM you are pretty much stuck with this AFAIK until there is a decision to maintain this logic in a way that is more consistent with the MongoDB API or otherwise allow access to the "raw" driver interface to perform these .update() operations.

For reference though, and has been alluded to, your general "shell" syntax or what would otherwise be supported in MongoDB specific drivers is like this with the deprecation of the $pushAll operator and the intention being to merge the functionality with the $push and $addToSet operators using the $each modifier:

db.collection.update(
   { "_id": ObjectId(refid) },    // should be important to "cast"
   {
      "$push": {
          "attachments": {
              "$each": arr
          }
      }
   }
)

So that syntax would work where it applies, but for you I am thinking that in "sails" it will not.

That gives you some food for thought, and some insight into the correct way to do things.

Someone who trying to push the element into an array is possible now, using the native mongodb library.

Considering the following mongodb collection object

{ 
"_id" : 5,
"attachments": [
    { 
        "id": "xxxxxxx",
        "subtype": "book",
        "title": "xxxx",
        "body": "xxxx" ,
        "filetype" : "xxxxx"
    },
    {
        "id": "xxxxxxx",
        "subtype": "book",
        "title": "xxxx",
        "body": "xxxx",
        "filetype": "xxxxx"
    }
]
}


 arr = [{
 'id':'123456',
 'subtype':'book',
 'title'  : 'c programing',
 'body'  :' complete tutorial for c',
 'filetype' : '.pdf'
 },
{
 'id':'123457',
 'subtype':'book',
 'title'  : 'Java programing',
 'body'  :' complete tutorial for Java',
 'filetype' : '.pdf'
 }
];

The following query can be used to push the array element to "attachments" at the end. $push or $addToSet can be used for this.

This will be inserting one object or element into attachments

db.collection('books').updateOne(
  { "_id": refid }, // query matching , refId should be "ObjectId" type
  { $push: { "attachments": arr[0] } } //single object will be pushed to attachemnts
 ).done(function (err, updElem) {
  console.log("updElem" + JSON.stringify(updElem));     
});

This will be inserting each object in the array into attachments

   db.collection('books').updateOne(
     { "_id": refid }, // query matching , refId should be "ObjectId" type
     { $push: { "attachments":{$each: arr} } } // arr will be array of objects
     ).done(function (err, updElem) {
           console.log("updElem" + JSON.stringify(updElem));     
    });

You are trying to insert an array as an element into your array. You may want to look at $pushAll as a short term solution. This operator is deprecated however see here .

Alternatively you can simply iterate over your array, and each iteration push an element from your array into attachments (this is the recommended approach by Mongo devs).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM