我的收藏看起来像这样。一个文档包含一个suggestions
数组。每个建议都可以有一系列emotes
。用户每个建议只能表现一次。请注意,文档可以有多个建议
{
id: 1,
suggestions:[
{
id: 463,
emotes:[
{
id: 35,
userId: 2
},
{
id: 23,
userId: 3
},
]
},
...
]
},
...
emotes
只能包含1个userId
实例。在推送一个新的表情元素之前,我需要检查userId
中是否存在emotes
。
我的尝试解决方案
(我正在使用更新命令语法来访问MongoDB 3.6功能。)
第一次尝试:addToSet
不起作用,因为emote
数组元素由userId
键入,而不是整个对象。
db.get().command({
update: 'channels',
updates:[
{
q:{
channelId,
"suggestions.id": suggestionOid,
},
u:{
$addToSet:
{
"suggestions.$[s].emotes": data
}
},
arrayFilters:[
{ 's.id': suggestionOid }
]
}
]
})
第二次尝试:以下不起作用。用户可能已经有另一个建议的表情,这将导致$ne
查询条件失败。这意味着用户每个文档只能表示一个建议,他们应该能够表达对文档的所有建议。
db.get().command({
update: 'channels',
updates:[
{
q:{
channelId,
'suggestions.emotes.userId': {$ne: userId },
"suggestions.id": suggestionOid,
},
u:{
$push:
{
"suggestions.$[s].emotes": data
}
},
arrayFilters:[
{ 's.id': suggestionOid }
]
}
]
})
我愿意将emotes
移动到一个新的集合或改变它的结构,如果这让事情变得更容易。我不能改变其他任何东西。
我通过使用$elemMatch
运算符解决了这个问题。
return channels.updateOne(
{
channelId,
"suggestions":{
$elemMatch:{
id: suggestionOid,
'emotes.user': {$ne: user }
}
},
},
{
$push:
{
"suggestions.$.emotes": data
}
}
)
来自mongodb docs https://docs.mongodb.com/manual/reference/operator/update/positional/的重要内容
如果查询使用否定运算符(例如$ ne,$ not或$ nin)匹配数组,则无法使用位置运算符更新此数组中的值。
但是,如果查询的否定部分位于$ elemMatch表达式内,则可以使用位置运算符更新此字段。