MongoDB更新数组对象的值,如果对象存在/ push新对象到数组不存在



首先,这是我的"用户";集合简化为只有相关字段:

[
{
_id: "10",
groups: [
"1"
],
notifications: [
{
notificationType: "message-like",
msgId: "3",
read: false,
likers: ["steve", "joe"]
}
]
},
{
_id: "20",
groups: [
"1",
"2"
],
notifications: [
{
notificationType: "message-like",
msgId: "1",
read: false,
likers: ["frank", "bob"]
},
{
notificationType: "message-like",
msgId: "2",
read: false,
likers: ["bob"]
}
]
}
]

I need to:

  1. 查找具有匹配的"_id">
  2. 查找具有匹配的notificationType"one_answers"msgId">
  3. 如果找到该对象,将其添加到" likeers "数组,将通知对象移动到第一个位置,并设置&;read&;
  4. 如果没有找到对象,将一个新的通知对象推送到数组

基本上,我需要在MongoDB中做以下操作:

for (let doc of documents) {
if (doc._id === "20") {
let notificationFound = false
doc.notifications.forEach((notif, i) => {
if (
notif.notificationType === "message-like"
&& notif.msgId === "2"
) {
notif.likers.push("joe")
if (notif.read === true) notif.read = false
notifications.unshift(notifications.splice(i, 1)[0]) //move notification to 1st position
notificationFound = true
}
})
if (!notificationFound) doc.notifications.push(newNotificationObject)
}
}

在MongoDB/Mongoose中做这件事的干净方法是什么?

您可以使用findOneAndUpdate方法和聚合管道

const mongoose = require('mongoose');
const { Schema } = mongoose;
const notificationSchema = new Schema({
notificationType: String,
msgId: String,
read: Boolean,
likers: [String]
});
const userSchema = new Schema({
_id: String,
groups: [String],
notifications: [notificationSchema]
});
const User = mongoose.model('User', userSchema);
const targetId = "20";
const targetType = "message-like";
const targetMsgId = "2";
const newLiker = "joe";
const newNotificationObject = {
notificationType: targetType,
msgId: targetMsgId,
read: false,
likers: [newLiker]
};
User.findOneAndUpdate(
{ _id: targetId },
[
{
$set: {
notifications: {
$let: {
vars: {
idx: {
$indexOfArray: [
"$notifications",
{ $elemMatch: { notificationType: targetType, msgId: targetMsgId } }
]
},
notFound: -1
},
in: {
$cond: [
{ $eq: ["$$idx", "$$notFound"] },
{ $concatArrays: ["$notifications", [newNotificationObject]] },
{
$concatArrays: [
[
{
$mergeObjects: [
{ $arrayElemAt: ["$notifications", "$$idx"] },
{
likers: { $concatArrays: [["$notifications.$$idx.likers", newLiker]] },
read: false
}
]
}
],
{ $slice: ["$notifications", 0, "$$idx"] },
{ $slice: ["$notifications", { $add: ["$$idx", 1] }, { $size: "$notifications" }] }
]
}
]
}
}
}
}
}
],
{ new: true }
)
.then(updatedDoc => {
console.log('Updated document:', updatedDoc);
})
.catch(err => {
console.error('Error updating document:', err);
});

明白了。目前运行良好:

const newNotificationObject = {
content: 'New Message Like',
date: Date.now(),
notificationType: 'message-like',
likers: [newLiker],
msgId: msgId
}
await User.updateOne(
{ 
$and: [
{ _id: userId }, 
{ 'notifications.notificationType': 'message-like' },  
{ 'notifications.msgId': msgId }
]
}, 
{
$set: {
'notifications.$[i].read': false,
'notifications.$[i].date': Date.now()
},
$push: { 'notifications.$[i].likers': newLiker }
},
{
arrayFilters: [ { 'i.likers': { $nin: newLiker } } ]
}
)
.then(async (docs1) => {
if (docs1.matchedCount > 0) res.json(true)
else {
await User.updateOne({ _id: userId }, { $push: { notifications: newNotificationObject } })
.then(docs2 => {
if (docs2.matchedCount > 0) res.json(true)
else throw new Error('Could not add notification')
})
.catch(err => { throw new Error(err) })
}
})
.catch(err => { throw new Error(err) })

最新更新