Alice
Alice

Reputation: 205

How to set array length after updating it via $addToSet in mongodb?

Document structure looks like this,

{
    blacklists:[]         // elements should be unique
    blacklistsLength:0    // length of blacklists
}

Adding sets of value to blacklists is easy.

db.posts.update({_id:...}, {$addtoSet:{blacklists:{$each:['peter', 'bob', 'steven']}}});

But How can I update blacklistLength at the same time to reflect the changes?

Upvotes: 0

Views: 2090

Answers (4)

user892729
user892729

Reputation: 41

As you upsert items into the database, simply query the item to see if it's in your embedded array. That way, you're avoiding pushing duplicate items, and only incrementing the counter as you add new items.

q = {'blacklists': {'$nin': ['blacklist_to_insert'] }}
u = {
 '$push' : {'blacklists': { 'blacklist_to_insert' } },
 '$inc' : {'total_blacklists': 1 }
}
o = { 'upsert' : true }

db.posts.update(q,u,o)

Upvotes: 0

Remon van Vliet
Remon van Vliet

Reputation: 18625

This is not possible. Either you have

  1. Update the length seperately using a subsequent findAndModify command or

  2. You can do it per name and rewrite the query using a negation in your criteria and $push rather than $addToSet (not necessarily needed but a lot faster with large blacklists since addToSet is always o(n) regardless of indexes) :

    db.posts.update({_id:..., blacklists:{$ne:'peter'}}, {$push:{blacklists:{'peter'}},$inc:{blacklistsLength: 1}});
    

The latter being perfectly safe since the list and the length are adjusted atomically but obviously has slightly degraded performance. Since it also has the benefit of better overall performance due to the $push versus $addToSet performance issue on large arrays (and blacklists tend to become huge and remember that the $push version of the update uses an index on blacklist in the update criteria while $addToSet will NOT use an index during it's set scan) it is generally the best solution.

Upvotes: 4

Aurélien B
Aurélien B

Reputation: 4640

I had a similar problem, please see the discussion here: google groups mongo

As you can notice, following to this discussion, a bug was open: Mongo Jira

Upvotes: 0

Ijonas
Ijonas

Reputation: 151

Would the following not work?

db.posts.update({_id:...}, {
  $addtoSet:{blacklists:{$each:['peter', 'bob', 'steven']}},
  $set: {blacklistsLength: ['peter', 'bob', 'steven'].length}
});

Upvotes: 1

Related Questions