当前位置: 首页 > 知识库问答 >
问题:

$setIntersection失败,子文档数组不在集合中

琴俊良
2023-03-14

考虑以下文件:

{
    "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":"$表达式中不允许包含字段"

以及:

db.test.aggregate([ { "$project": { 
    "items": { "$setIntersection": [ "$item2", [ { "a": "b" } ] ] } } } 
])

失败原因:

“errmsg”:“字段路径“b”不以$开头”

使其工作的唯一方法是使用$litald运算符。

如果$setIntersect参数是子文档的数组而不是文档中的字段,为什么我们应该使用$litald运算符?

共有2个答案

齐才艺
2023-03-14

这似乎是MongoDB 3.2中的兼容性更改,因此是MongoDB 3.2中聚合兼容性更改中提到的预期行为:

在聚合管道中,数组元素不再被视为文字。相反,数组的每个元素现在都被解析为表达式。要将元素视为文本而不是表达式,请使用$literal操作符创建文本值。

司寇山
2023-03-14

这似乎是MongoDB 3.2的一个工件,它包含了一个更改,允许在直接插入文档属性的同时对数组进行注释。

例如,使用以下文档:

js prettyprint-override"> { "a": 1, "b": 2, "c": 3, "d": 4 }

然后“现在”可以在数组中标记这些元素,如:

db.collection.aggregate([
    { "$project": {
        "array": [
           { "field1": "$a", "field2": "$b" },
           { "field1": "$c", "field2": "$d" }
        ]
    }}
])

在以前的版本中(在本例中为MongoDB 2.6),您需要使用以下表达式:

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中允许的符号更改,否则在以前的版本中会出现“错误”。

因此,在以前的版本中,比如MongoDB 2.6。如果支持$setIntersection,则以下操作很好,因为所有值都被视为“文字”,除非实际引用文档中存在的数组:

db.collection.aggregate([
  { "$project": {
    "a": { 
      "$setIntersection": [
        [{"a": 1}],
        [{"a": 1}]
      ]
    }
  }}
])

当然,前提是作为一个集合,“集合”实际上包含一些东西。

但由于MongoDB 3.2允许对“插值数组”使用不同的语法,它现在希望“右侧”计算为文档或其他有效表达式中的属性。因此,现在需要使用$literal语法:

db.collection.aggregate([
  { "$project": {
    "a": { 
      "$setIntersection": [
        { "$literal": [{"a": 1}] },
        { "$literal": [{"a": 1}] }
      ]
    }
  }}
])

这通常归结为“你不能有你的蛋糕也吃它”的说法,“新”语法允许你用“插值”以一种很好的方式表达数组内容,而不必求助于其他表达式将内容“强制”成数组形式。

这样做的结果是,每个这样的表达式现在都希望“值”解析为属性或表达式,而不是直接被视为“文字”,如果您的意思是这样的,那么现在需要使用$文字操作符来表示。

因此,它实际上是版本间允许语法的“突破性”更改。但大多数人都应该很容易接受。

 类似资料:
  • 我的FiRecovery数据库中有一个名为Reports的集合,我已经在其中添加了文档。但我现在的问题是我想在报表中添加一个带有子集合的文档,有什么想法吗?

  • 我被android firstore文档和子集合弄糊涂了。 此示例将生成以下数据结构: 代码如下: 子集合和文档节点交替显示:a、c与b、d。 但是如何在没有d节点的情况下实现类似的数据结构(如下所示): 自。add方法仅适用于document而不适用于collection,我们不能只删除d(document),因为c(collection)没有add方法。 我应该如何修改我的代码?

  • 在我的集合的SnapshotListener中,我使用以下命令循环遍历文档: 在 for 循环中的每个文档中,让我们称之为 ,我在 Cloud Firestore 上还有另一个文档集合。我想检索内子集合中的所有文档(每个文档只有一个字符串字段)。我能够做一个来获取本身,我用它来获取字符串字段,但我不知道如何获取其子集合中的文档。

  • 考虑以下Firestore结构: 收藏 现在,我想查询宠物满足某些条件的人。例如,拥有两只以上宠物的人,或者拥有一只名为“ABC”的宠物的人。 这可能吗?

  • 我有一份这样的文件 上面的文档可以这样概括如下,便于理解。 我需要增加nums子文档中数量的值,该值位于产品子文档中,基于其\u id。 这是我迄今为止所尝试的,但它不起作用,因为我不知道如何捕获nums对象内的\u id,以便更新子子文档数组中的特定对象。 我怎样才能做到这一点?

  • 我是新来的mongo。我有以下收藏。 文件: 请求: 文档集合中的typeId是文档类型的id,其中请求中的typeId是也可以为空的外部字段。如何获得以下输出。