[SERVER-176] $addToSet | push unique item to array (WAS: Support for set type or set-like operations for arrays ) Created: 22/Jul/09  Updated: 12/Jul/16  Resolved: 11/Feb/10

Status: Closed
Project: Core Server
Component/s: Write Ops
Affects Version/s: None
Fix Version/s: 1.3.2

Type: New Feature Priority: Major - P3
Reporter: Michael Dirolf Assignee: Eliot Horowitz (Inactive)
Resolution: Done Votes: 14
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
related to SERVER-628 $addToSet : { $each : [ ] } Closed
Participants:

 Description   

Might be useful to have a set (unique array) type, or support set-like operations on arrays ($pushUnique). No real specific use case in mind, just something redis supports that seems cool.



 Comments   
Comment by Eliot Horowitz (Inactive) [ 11/Feb/10 ]

going to resolve this since $addToSet works, and added new case for { $addToSet :

{ $each : [] }

}

Comment by auto [ 26/Jan/10 ]

Author:

{'login': 'erh', 'name': 'Eliot Horowitz', 'email': 'eliot@10gen.com'}

Message: $addToSet mostly working SERVER-176
http://github.com/mongodb/mongo/commit/556c5a6d7d0fdf71a3f43960d82d4e0cf723a81b

Comment by Eliot Horowitz (Inactive) [ 26/Jan/10 ]

decided on the name $addToSet

Comment by Andrew Bryan [ 26/Jan/10 ]

I'm also holding my breath for this feature... it would it easier to combine more operations into a single call.

For example (perl).. if you had a document with tags (indexed), you could update or create and add multiple tags (while staying unique) with:

$coll->update(

{ '_id' => $id }

,
{
'$set' =>

{ 'foo' => $bar }

,
'$pushAllUnique' =>

{ 'tags' => \@tags }

,
},

{ 'upsert' => 1 }

,
);

Without the $pushAllUnique you'd probably have to do (num new tags + 1) updates...

Comment by Eliot Horowitz (Inactive) [ 19/Jan/10 ]

just blocking on name.

Comment by Gregg Lind [ 29/Dec/09 ]

I would also really like set() as a first class type in mongo, for the reasons that Ian White mentioned, for things like $pushAllUnique.

Comment by Eliot Horowitz (Inactive) [ 05/Dec/09 ]

I understand. I'm just saying if there is in fact with the current functionality, that should be in its own case.
You can't modify _id, so i'm not sure what's going on yet.

Comment by Etienne Robillard [ 05/Dec/09 ]

The comments on this page are linking to this page:

http://www.mongodb.org/display/DOCS/Updating#Updating-%24pushaUniqueValue

If its belong here or not I don't know, I just followed a link in hope to find a work-around
for supporting merge operations.

Regards, Etienne

Comment by Eliot Horowitz (Inactive) [ 04/Dec/09 ]

if you can reproduce your error - can you create a new case with the error.
doesn't really belong here.

Comment by Etienne Robillard [ 04/Dec/09 ]

Yes, i use something like

> Manager.update(dict(_id=data['_id']),

{"$push": data}

)

pymongo-1.1.1 and mongodb 1.1.3 (using 32bit binaries for linux)

my use case is a simple yaml file that i want to use as a fixture, to merge
into a MongoDB collection. i then use the yaml module to convert the file
into a dict instance, where it contains the new "updated" set.

Regards,
Etienne

Comment by Eliot Horowitz (Inactive) [ 04/Dec/09 ]

Were you trying to modify _id?

Comment by Etienne Robillard [ 04/Dec/09 ]

Got this in the logs while attempting the solutions proposed above:

Fri Dec 4 12:11:13 User Exception Mod on _id not allowed
Fri Dec 4 12:11:13 test4.movies Caught Assertion update, continuing
Fri Dec 4 12:11:13 update test4.movies query:

{ _id: "movies2" }

exception userassert:Mod on _id not allowed 0ms

should it be possible to use $set or $push to 'merge' a set with another ?

Thanks!
Etienne

Comment by Ian White [ 30/Nov/09 ]

Mathias's solutions are both helpful but neither one is a replacement for a $pushAllUnique, which is what I'd really find useful. (Other set-like operations would be cool, but all I really need is $pushAllUnique, and $pullAll which Mongo already has.)

The first solution (objects) is problematic because AFAIK you can't index types in a general way. You can index types.apple, but then you need a different index for each possible type of fruit.

The second solution is great when you just want to $push one item, but it's not sufficient if you want to $pushAll multiple items and retain uniqueness. In that case, you have to do multiple updates, which is problematic if you want the update to be atomic.

Comment by John Nunemaker [ 18/Nov/09 ]

Good point. This solves the push unique issue. I can still see merit in other set operations but thanks for posting that.

Comment by Mathias Stearn [ 17/Nov/09 ]

Since this was posted to twitter I thought I'd add another way to do this with current mongod:

update({"_id"="fruits", "types": {"$ne": "orange"}}, {"$push": {"types": "orange"}})

This should be at least as fast as first-class sets in BSON, at least for smallish sizes.

Comment by John Nunemaker [ 17/Nov/09 ]

Mathias,
Interesting idea, though the true is really just taking up extra space. I've been using arrays and doing checks before adding to the array. It would be awesome to just have a set type and never have to think about if the value is there or not.

Also, set operations like superset, subset, and intersection could be very cool.

Comment by Mathias Stearn [ 24/Aug/09 ]

I use objects for this. For example I might have a document like {"_id": "friuts", "types": {"apple": true}} then I can use update(

{"_id"="fruits"}

, {"$set": {"types.orange", true}}) when I need to add to the set. This works with both JSON and JavaScript both of which lack a real set type.

Rather than add a set type it may make sense to optimize this case (if you aren't already)

Generated at Thu Feb 08 02:53:16 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.