考虑以下文件:
{
"item1" : [
{
"a" : 1,
"b" : 2
}
],
"item2" : [ "a", "b" ]
}
以下查询:
db.test.aggregate([
{ "$project": { "items": { "$setIntersection": [ "$item1", "$item2" ] } }}
])
返回预期结果:
{ "_id" : ObjectId("5710785387756a4a75cbe0d1"), "a" : [ ] }
如果文档如下所示:
{ "item2" : [ "a", "b" ] }
然后:
db.test.aggregate([ { "$project": {
"a": { "$setIntersection": [ "$item2", [ "a" ] ] } } }
])
收率:
{ "_id" : ObjectId("5710785387756a4a75cbe0d1"), "a" : [ "a" ] }
但是
db.test.aggregate([
{ "$project": { "items": { "$setIntersection": [ "$item2", [ { "a" : 1, "b" : 2 } ] ] } } }
])
失败了:
" ERRMSG" :" $ expressions;#34;
中不允许使用字段包含
和
db.test.aggregate([ { "$project": {
"items": { "$setIntersection": [ "$item2", [ { "a": "b" } ] ] } } }
])
失败了:
" ERRMSG" :" FieldPath' b'不以$"
开头
使这项工作的唯一方法是使用$literal
运算符。
如果$literal
参数是子文档数组而不是文档中的字段,我们为什么要使用$setIntersection
运算符?
答案 0 :(得分:1)
这似乎是MongoDB 3.2的一个工件,它包含了一个允许在直接插入文档属性时注释数组的更改。
例如,使用如下文档:
{ "a": 1, "b": 2, "c": 3, "d": 4 }
然后你“现在”允许在数组中标记这些元素,例如:
db.collection.aggregate([
{ "$project": {
"array": [
{ "field1": "$a", "field2": "$b" },
{ "field1": "$c", "field2": "$d" }
]
}}
])
在以前的版本(在本例中为MongoDB 2.6)中,您需要使用此$map
表达式:
db.collection.aggregate([
{ "$project": {
"array": {
"$map": {
"input": ["A","B"],
"as": "el",
"in": {
"$cond": {
"if": { "$eq": [ "$$el", "A" ] },
"then": { "field1": "$a", "field2": "$b" },
"else": { "field1": "$c", "field2": "$c" }
}
}
}
}
}}
])
或者在之前的版本中,使用$unwind
和$group
进行更长时间的渲染,但是将“源”数组与其他数据进行转置的基本原则相同。但重点是MongoDB 3.2中允许的符号变化,否则在先前版本中会出现“错误”。
因此在先前的版本中,比如支持$setIntersection
的MongoDB 2.6.x,那么以下工作正常,因为除非实际引用文档中存在的数组,否则所有值都被视为“文字”:
db.collection.aggregate([
{ "$project": {
"a": {
"$setIntersection": [
[{"a": 1}],
[{"a": 1}]
]
}
}}
])
当然,"collection"
作为一个集合实际上有一些东西。
但是由于MongoDB 3.2为“插值数组”提供了不同的语法,现在它希望“右侧”从文档或其他有效表达式中评估属性。所以现在需要$literal
语法:
db.collection.aggregate([
{ "$project": {
"a": {
"$setIntersection": [
{ "$literal": [{"a": 1}] },
{ "$literal": [{"a": 1}] }
]
}
}}
])
这通常归结为“你不能吃蛋糕而且吃得太多”的说法。 “新”语法允许您以一种很好的方式用“插值”表达数组内容,而无需借助其他表达式将内容“强制”为数组形式。
这样做的结果是每个这样的表达式现在都期望“值”解析为属性或表达式,而不是直接被视为“文字”,并且你的意思是这样的,您现在需要使用$literal
运算符表达。
因此,它实际上是版本之间允许语法的“突破”变化。但大多数人应该容易接受的一个。
答案 1 :(得分:0)
这似乎是MongoDB 3.2中的兼容性更改,因此是Aggregation Compatibility Changes in MongoDB 3.2中提到的预期行为:
数组元素不再被视为聚合管道中的文字。相反,数组的每个元素现在都被解析为表达式。要将元素视为文字而不是表达式,请使用
$literal
运算符创建文字值。