0

I have a collection Playlist that contains an array of items

{

    userId: {
        type        : String,
        required    : true,
        index       : true,
        unique      : true
    },

    items: [
        {
            id: { // do not mix up with _id, which is the autogenerated id of the pair {id,type}. ID is itemId
                type        : Schema.Types.ObjectId
            },
            type: {
                type        : String
            }
        }
    ]

}

Mongo automatically adds the _id field to the items when I push a pair {id,type} to items (but I don't care about it).

Now I would like to remove several "pairs" at once from the items array.

I have tried using $pullAll but it requires an exact match, and I do not know the _id, so it does not remove anything from items

playlistModel.update({userId:userId},{$pullAll:{items:[{id:"123",type:"video"},{id:"456",type:"video"}]}},null,function(err){

I have tried using $pull with different variants, but it removed ALL objects from items

playlistModel.update({userId:userId},{$pull:{items:{"items.id":{$in:["123","456"]}}}},null,function(err){

playlistModel.update({userId:userId},{$pull:{items:{$in:[{id:"123",type:"video"},{id:"456",type:"video"}]}}},null,function(err){

Am I missing something or am I asking something that isn't implemented?

If the latter, is there a way I can go around that _id issue?

APE
  • 1,130
  • 7
  • 21
  • Didn't clearly understand what you are trying to do here. You want to remove `several pairs` but not `all the pairs` which match. What does that even mean? – Ankit Gomkale Apr 06 '17 at 08:43
  • Let's say I have a Playlist document whose "items" array is [{id:"123",type:"video"},{id:"456",type:"video"},{id:"789",type:"video"}] (note that mongodb adds _id to those 3 objects in items) I want for example to remove {id:"123",type:"video"} and {id:"456",type:"video"} from "items" in 1 query (just leaving the other objects, here in this example {id:"789",type:"video"}) I think the confusion with the "exact match" comes from the fact that I don't know the _id of the objects I want to remove. Hope that makes sense now! – APE Apr 06 '17 at 21:43
  • Why not disable the `_id` field creation for embedded document ? Take a look at this http://stackoverflow.com/questions/17254008/stop-mongoose-from-creating-id-property-for-sub-document-array-items – s7vr Apr 06 '17 at 23:21
  • Sounds great! I will have a look at that :) – APE Apr 06 '17 at 23:46

2 Answers2

1

OK I found a way that works using $pull:

playlistModel.update({userId:userId},{$pull:{items:{id:{$in:["123","456"]}}}},null,function(err){ 

It doesn't take the type into account but I can't see any issue with that since the id is unique across all types anyway.

Although I will wait a bit to see if someone has a better solution to offer

EDIT

With Veeram's help I got to this other solution, which IMO is more elegant because I don't have _ids that I don't need in the database, and the $pullAll option seems more correct here

var playlistItemSchema = mongoose.Schema({
    id: { // do not mix up with autogenerated _id. id is itemId
        type        : Schema.Types.ObjectId
    },
    type: {
        type        : String
    }
},{ _id : false });

var schema = new Schema({

    userId: {
        type        : String,
        required    : true,
        index       : true,
        unique      : true
    },

    items: [playlistItemSchema]

});


playlistModel.update({userId:userId},{$pullAll:{items:[{id:"123",type:"video"},{id:"456",type:"video"}]}},null,function(err){
APE
  • 1,130
  • 7
  • 21
0

tips: you can use _id field to handle your playlistModel data.

mongoose api : new mongoose.Types.ObjectId to generate an Object_id

let _id=new mongoose.Types.ObjectId;
     playlistModel.updateMany({_id:_id},{ $set: { name: 'bob' }}).exec(data=>{console.log('exec OK')});
vingo
  • 26
  • 3