Update array containing object only if that object doesn't exist in the array?


#1

I want to make an insert as an array similar to addToSet but only add this array containing objects if that objects doesn’t yet exist in the array.

Basically an addToSet but with checking if the exact object exists.

  Meteor.users.update({_id: toUserId}, { $addToSet:{
    {
        messages: messageId, userId: fromUserId
    }
  } });

Is there a way to do this with mongo/eteor?


#2

Can you not use the $in function of mongodb?


#3

Try also upsert…

Optional. If set to true, creates a new document when no document matches the query criteria. The default value is false, which does not insert a new document when no match is found.

db.books.update( { item: "ZZZ135" }, { item: "ZZZ135", stock: 5, tags: [ "database" ] }, { upsert: true } )


#4

I will check out $in later. The thing is I’m not creating a document. I only want to reference IDs of messages to the user’s document. So what I’m doing is adding to an array of message IDs + the id of the user who sent the message, So that then I can get those IDs and search for the messages with those IDs in the messaging part of our app.

It’s something like:

profile: {
   ...
},
services: {
   ...
}
messages: [
   {messageId: abc, fromUserId: def},
   {messageId: cba, fromUserId: fed},
   ...
]

#5

So, I’m going to ask today’s stupid question :confused: - why not use a separate collection? Could the user object become unreasonably big over time?


#6

Honestly, I’m not sure. I’m not really proficient with database schemas. I just thought that the easiest way would be to only reference the messages via id’s in the user object. The size of the user object could be handled by not publishing the fields of the messages when not required.

The reason why I decided for this approach was because I considered it the easiest one to get the ids. It’s just Meteor.user().messages.

So how would you do it? I tried to put things all in one messages collection but it kind of got complicated which is why I re-considered doing it how I am doing it now.

Would you create one collection just for referencing the id’s and one collection for the actual messages?


#7

That would depend on whether the messaging is one-to-one or one-to-many. For one-to-one I would just embed the message text in the message object:

{ toUserId, fromUserId, createdAt, status, messageText }

Otherwise, two collections

{ toUserId, fromUserId, status, messageId }
{ messageId, createdAt, messageText }

Clearly, as soon as you get to two or more collections there’s a great temptation to normalise and group ids in arrays to avoid duplication. Honestly, it’s rare that the space savings or performance differences (if you get the indexing right) are outweighed by the complexity of the code.

My opinion only. YMMV :slight_smile:


#8

Thank you very much for the feedback :slight_smile: !