查询和筛选带有'点'的ChangeStream文档'。'
我有一个看起来像的文件
{
components: { weapon: { type: "Sword" }, health: { value: 10 } }
type: "Monster"
}
我正在使用返回的change stream
{
operationType: 'update',
updateDescription: {
updatedFields: { 'components.weapon': [Object] }
}
}
我想向聚合管道添加查询以过滤出组件的所有not更新,即,如果类型字段已更新,我不希望获得更新。
我的查询看起来像
{ $match: { "updateDescription.updatedFieldsponents.weapon": { $exists: true } }
但是这不起作用,因为updatedFields上的字段是'components.weapon'而不是components:{武器:..}。
如果可以使用括号表示法,我会这样做
{ $match: { "updateDescription.updatedFields['components.weapon']": { $exists: true } }
但是在MongoDB语法中不允许这样做(或者至少它不起作用)。
是否有解决方案?
回答如下:这是一个棘手的问题,但是这里有一些可靠的原因,并且normal MongoDB文档案例将不包括这样的“ dotted field”。因此,确实需要一些特殊的处理。
这里的基本情况是,您基本上需要将包含“虚线字段”的文档中的"key"
转换为实际上是“字符串”,然后只需在该字符串中查找"component"
的存在。
简而言之,您基本上想要pipeline
的表达式为watch()
,如下所示:
watch()
这是使用const pipeline = [
{ "$match": {
"$expr": {
"$ne": [
{ "$size": {
"$filter": {
"input": {
"$objectToArray": "$updateDescription.updatedFields"
},
"cond": {
"$eq": [{ "$indexOfCP": [ "$$this.k", "component" ], }, -1]
}
}
}},
0
]
}
}}
];
将$objectToArray
对象转换为$objectToArray
和updatedFields
属性的数组,而不是命名键的数组。此时,结果值将如下所示:
k
这允许使用v
中的表达式将now array与[
{
"k": "coponents.weapon",
"v": "Sword"
}
]
操作一起使用,该表达式测试$filter
属性值中字符串的存在。如果不是$filter
(对于未找到),则该值中包含$indexOfCP
的任何元素都是唯一保留的元素,并且匹配结果数组中的元素。
NOTE如果您具有MongoDB 4.2,则可能需要查看
$indexOfCP
运算符,而不是k
。不必仅仅测试字符串中字符串的“存在”,但如果您的用例需要,则正则表达式当然可以做更多的工作。这里适当,您可能会从字符串的开头搜索到包含的“点”,用
-1
内的"component"
代替:$regexMatch
由于将其作为数组返回,因此您可以测试 选择文档$regexMatch
,以查看一旦删除$indexOfCP
值后,现在的[[filtered数组中实际上是否还剩下任何东西。如果没有,并且大小确实为$indexOfCP
,则通过cond
丢弃结果,这也是允许在$filter
中使用聚合表达式的主要运算符。当然,所有要做的是$filter
结果中可能还有其他更改的字段,则实际上您需要对该类型采用相同的 "$not": { "$regexMatch": { "input": "$$this.k", "regex": /^components\./ } }
操作类型,才能从结果:$size
请注意,这里所使用的操纵过程,然后实际上将$size
的添加基本上是reverses
"component"
内容以其原始形式返回,而没有不需要的键。为了演示,这里是一个实际的完整清单,它复制具有这种结构的集合所做的更改,并包括
watcher
管道,以便静音不必要的更改:]]0