5

I am working on a Node.js application that is using a MongoDB database with Mongoose. I've been stuck in this thing and didn't come up with the right query.

Problem:

There is a collection named chats which contain embedded documents (rooms) as an array of objects. I want to delete these embedded documents (rooms) through Ids which are in the array.

  {
    "_id": "ObjectId(6138e2b55c175846ec1e38c5)",
    "type": "bot",
    "rooms": [
      {
        "_id": "ObjectId(6138e2b55c145846ec1e38c5)",
        "genre": "action"
      },
      {
        "_id": "ObjectId(6138e2b545c145846ec1e38c5)",
        "genre": "adventure"
      }
    ]
  },
  {
    "_id": "ObjectId(6138e2b55c1765846ec1e38c5)",
    "type": "person",
    "rooms": [
      {
        "_id": "ObjectId(6138e2565c145846ec1e38c5)",
        "genre": "food"
      },
      {
        "_id": "ObjectId(6138e2b5645c145846ec1e38c5)",
        "genre": "sport"
      }
    ]
  },
  {
    "_id": "ObjectId(6138e2b55c1765846ec1e38c5)",
    "type": "duo",
    "rooms": [
      {
        "_id": "ObjectId(6138e21c145846ec1e38c5)",
        "genre": "travel"
      },
      {
        "_id": "ObjectId(6138e35645c145846ec1e38c5)",
        "genre": "news"
      }
    ]
  }

I am converting my array of ids into MongoDB ObjectId so I can use these ids as match criteria.

const idsRoom = [
  '6138e21c145846ec1e38c5',
  '6138e2565c145846ec1e38c5',
  '6138e2b545c145846ec1e38c5',
];

const objectIdArray = idsRoom.map((s) => mongoose.Types.ObjectId(s));

and using this query for the chat collection. But it is deleting the whole document and I only want to delete the rooms embedded document because the ids array is only for the embedded documents.

Chat.deleteMany({ 'rooms._id': objectIdArray }, function (err) {
  console.log('Delete successfully')
})

I really appreciate your help on this issue.

Ven Nilson
  • 969
  • 4
  • 16
  • 42
  • [this](https://stackoverflow.com/questions/15121758/using-mongodb-pull-to-delete-documents-within-an-array) looks very similar, you dotn need to delete, you want to update, and change the array, delete refers only to documents not embeded documents – Takis Sep 09 '21 at 21:34
  • @Takis_ But how can we delete without knowing the `parent Id` we only have Ids for the embedded documents. – Ven Nilson Sep 09 '21 at 21:41
  • oh ok its not the same completly,you want to search with a path, i think you need to make an index on that rooms._id field to be fast, if you will search by it (multikey index) – Takis Sep 09 '21 at 21:45

1 Answers1

2

You have to use $pull operator in a update query like this:

This query look for documents where exists the _id into rooms array and use $pull to remove the object from the array.

yourModel.updateMany({
  "rooms._id": {
    "$in": [
      "6138e21c145846ec1e38c5",
      "6138e2565c145846ec1e38c5",
      "6138e2b545c145846ec1e38c5"
    ]
  }
},
{
  "$pull": {
    "rooms": {
      "_id": {
        "$in": [
          "6138e21c145846ec1e38c5",
          "6138e2565c145846ec1e38c5",
          "6138e2b545c145846ec1e38c5"
        ]
      }
    }
  }
})

Example here.

Also you can run your query without the query parameter (in update queries the first object is the query) like this and result is the same. But is better to indicate mongo the documents using this first object.

J.F.
  • 13,927
  • 9
  • 27
  • 65