简体   繁体   中英

How to get an object from a MongoDB nested array

I have a MongoDB collection for storing chat objects with messages embedded as a nested array. The entire collection looks like this:

chats = [
  {
    _id: 0,
    messages: [
      {
        _id: 0,
        text: 'First message'
      },
      {
        _id: 1,
        text: 'Second message'
      }
    ]
  },
  {
    _id: 1,
    messages: []
  }
]

I would like to update a single message and return it to the user. I can update the message like this (in Node):

const chat = chats.findOneAndUpdate({
        _id: ObjectId(chatID),
        "messages._id": ObjectId(messageID)
    }, {
        $set: {
            "messages.$.text": newText
        }
    });

The issue is that this query updates a message and returns a chat object, meaning that I have to look for an updated message in my code again. (ie chat.messages.find(message => message._id === messageID) ).

Is there a way to get a message object from MongoDB directly? It would also be nice to do the update in the same query.

EDIT: I am using Node with mongodb.

Thank you!

Since MongoDB methods findOneAndUpdate , findAndModify do not allow to get the updated document from array field,

  • projection will return updated sub document of array using positional $ after array field name
  • returnNewDocument: true will return updated(new) document but this will return whole document object

The problem is, MongoDB cannot allowing to use a positional projection and return the new document together

For temporary solution try using projection , this will return original document from array field using $ positional,

const chat = chats.findOneAndUpdate(
  {
    _id: ObjectId(chatID),
    "messages._id": ObjectId(messageID)
  }, 
  { $set: { "messages.$.text": newText } },
  { 
    projection: { "messages.$": 1 }
  }
);

Result:

{
    "_id" : 0.0,
    "messages" : [ 
        {
            "_id" : 0.0,
            "text" : "Original Message"
        }
    ]
}

To get an updated document, a new query could be made like this:

const message = chats.findOne({
    _id: ObjectId(chatID),
    "messages._id": ObjectId(messageID)
  }, {
    projection: {'messages.$': 1},
}).messages[0];

Result:

{
    "_id": 0.0,
    "text": "New message",
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM