How to check if Mongo's $addToSet was a duplicate or not
Asked Answered
P

3

6

I am using Mongoskin + NodeJS to add new keywords to MongoDB. I want to notify the user that the entry was a duplicate but not sure how to do this.

/*
* POST to addkeyword.
*/
router.post('/addkeyword', function(req, res) {
var db = req.db;
db.collection('users').update({email:"[email protected]"}, {'$addToSet': req.body }, function(err, result) {
    if (err) throw err;
    if (!err) console.log('addToSet Keyword.' );
}); 
});

The result does not seem to be of any use since it doesn't state if the keyword was added or not.

Priestly answered 8/5, 2014 at 14:14 Comment(0)
L
4

At least in the shell you can differentiate if the document was modified or not (see nModified).

> db.test4.update({_id:2}, {$addToSet: {tags: "xyz" }})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

> db.test4.update({_id:2}, {$addToSet: {tags: "xyz" }})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })

Update for Node

When you use collection.update(criteria, update[[, options], callback]); you can retrieve the count of records that were modified.

From the node docs

callback is the callback to be run after the records are updated. Has two parameters, the first is an error object (if error occured), the second is the count of records that were modified.

Another Update

It seems at least in version 1.4.3 the native Mongo Node driver is not behaving as documented. It is possible to work around using the bulk API (introduced in Mongo 2.6):

var col = db.collection('test');
// Initialize the Ordered Batch
var batch = col.initializeOrderedBulkOp();
batch.find({a: 2}).upsert().updateOne({"$addToSet": {"tags": "newTag"}});
// Execute the operations
batch.execute(function(err, result) {
  if (err) throw err;
  console.log("nUpserted: ", result.nUpserted); 
  console.log("nInserted: ", result.nInserted); 
  console.log("nModified: ", result.nModified); // <- will tell if a value was added or not
  db.close();
});
Lissie answered 8/5, 2014 at 14:28 Comment(4)
It is good to note that this is a new feature, before 2.6 it would record modified even if it wasn't.Dulcet
Are you sure it works as described for MongoDb 2.6? I just tried and it returned 1 in callback for this case. So it seems it returns matched count, but not modified count. I use MongoDB 2.6.0 on Windows.Knot
@AndreiBeziazychnyi Are you using the latest driver? Most likely the w API change required driver changes as wellDulcet
I updated driver before checking, latest version is 1.4.3. Could you confirm that described method works for you in node.js?Knot
K
1

You could use db.users.findAndModify({email:"[email protected]"},[],{'$addToSet': { bodies: req.body }},{'new':false}). Pay attention to new:false switcher, it allows you to get document before update and you could check whether array contained item before update. However, it could be problematic approach if your documents are big, because you analyze it on client side.

P.S. Your original query with $addToSet is wrong: field name is missing.

Edit: I tried to use count returned by update, but it returns 1 for me in all cases. Here is the code I used for test with MongoDB 2.6:

var MongoClient = require('mongodb').MongoClient;

MongoClient.connect('mongodb://localhost:27017/mtest', function(err, db) {
   if(err) throw err;

   db.collection('test').insert({_id:1,bodies:["test"]},function(err,item){

     db.collection('test').update({_id:1},{$addToSet:{bodies:"test"}}, function(err,affected){
        if(err) throw err;
        console.log(affected); //1 in console

    });
 });

});
Knot answered 8/5, 2014 at 14:23 Comment(0)
H
0

i am update a array from Collection with this JSON:

{
    "<arrayname>":"<value>"
}

route.js

routes.post("/api/:id", Controller.addOne);

Controller.js

async addOne(req, res) {
    //juryman id to list add
    if (Object.keys(req.body).length === 1) {
      console.log("Size 1");
    }
    await Session.findOneAndUpdate(
      { _id: req.params.id },
      { $addToSet: req.body }
    )
      .then(function(success) {
        res.send("Successfully saved.");
      })
      .catch(function(error) {
        res.status(404).send(error);
      });
  },

I have five arrays in my Collection and this changes the JSON array name-value and updates correctly, the respectively Collection array. This works only for one item.

Hayleyhayloft answered 27/2, 2020 at 21:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.