【问题标题】:Mongodb use find (not aggregation) to get only one nested sub-documentmongodb使用find(不是聚合)只获取一个嵌套子文档
【发布时间】:2021-08-22 06:12:34
【问题描述】:

在我的集合中,我有两个嵌套的子文档,分别称为“级别”和“模块”:

[
  {
    "_id": 1,
    "course": "course1",
    "levels": [
      {
        "level_id": "C1L1",
        "name": "course 1 - level1",
        "modules": [
          {
            "module_id": "C1L1M1",
            "name": "level 1module1"
          },
          {
            "module_id": "C1L1M2",
            "name": "level 1 module2"
          },
          
        ]
      },
      {
        "level_id": "C1L2",
        "name": "course 1 - level2",
        "modules": [
          {
            "module_id": "C1L2M1",
            "name": "level 2 module1"
          },
          {
            "module_id": "C1L1M2",
            "name": "level 2 module2"
          },
          
        ]
      },
      
    ]
  },
  {
    "_id": 2,
    "course": "course2",
    "levels": [
      {
        "level_id": "C2L1",
        "name": "course 2 - level1",
        "modules": [
          {
            "module_id": "C2L1M1",
            "name": "level1 module1"
          },
          {
            "module_id": "C2L1M2",
            "name": "level1 module2"
          },
          
        ]
      },
      {
        "level_id": "C2L2",
        "name": "course 2 - level2",
        "modules": [
          {
            "module_id": "C2L2M1",
            "name": "level 2 module1"
          },
          {
            "module_id": "C2L1M2",
            "name": "level 2 module2"
          },
          
        ]
      },
      
    ]
  },
]

我只需要获取一个符合条件的子文档,例如 {"module_id": "C1L2M1"} 。 我已经确切知道如何使用聚合框架来实现这一点,但我想知道是否有任何解决方案可以避免聚合。

我只能在投影中使用$elemMatch 检索一个嵌套子文档,但我不知道如何过滤第二个嵌套子文档(在我的示例中为模块)。

我想要的结果是查询模块“C1L2M1”并且只得到这个:

{
  "module_id": "C1L2M1",
  "name": "level 2 module1"
}

这里是一个示例游乐场:https://mongoplayground.net/p/uwBOh1MkQm-

【问题讨论】:

  • 我想知道是否有任何避免聚合的解决方案 => 不,没有聚合过滤器运算符是不可能的,您可以在从 MongoDB 开始的查找投影中使用聚合投影运算符4.4.像 $map/$filter..
  • 这就是我教的。 >= 4.4 是可能的吧?
  • @turivishal 谢谢,你知道在 find 投影中使用聚合运算符在性能方面是更快还是更慢(或相等:))?
  • 我认为两者是相等的,他们在documentation 中没有提到,如果你想确保 100% 然后在两个查询中通过 .explain() 检查性能。
  • @turivishal 非常感谢。您要发布答案以便我接受它是正确的吗?

标签: mongodb mongodb-query


【解决方案1】:

这是一个不可读的混乱,使用find 命令得到你想要的结果:

db.collection.find(
{
    "levels.modules.module_id": "C1L2M1"
},
{
    _id: 0,
    module: {
        $first: {
            $filter: {
                input: {
                    $map: {
                        input: "$levels",
                        as: "l",
                        in: {
                            $first: {
                                $filter: {
                                    input: "$$l.modules",
                                    as: "m",
                                    cond: { $eq: ["$$m.module_id", "C1L2M1"] }
                                }
                            }
                        }
                    }
                },
                as: "x",
                cond: { $ne: ["$$x", null] }
            }
        }
    }
})

它输出以下内容:

{
    "module" : {
        "module_id" : "C1L2M1",
        "name" : "level 2 module1"
    }
}

https://mongoplayground.net/p/KZHwvKdgY9f

【讨论】:

    【解决方案2】:

    我想知道有没有什么办法可以避免聚合。

    除了聚合没有其他选择,要达到预期的结果,您必须使用Aggregation Array Expression Operators。


    如果你真的想使用 find 方法,那么你可以从 MongoDB 4.4 开始使用 Aggregation Expression,

    从 MongoDB 4.4 开始,作为使 find() 和 findAndModify() 投影与聚合的 $project 阶段一致的一部分,
    find() 和 findAndModify() 投影可以接受聚合表达式和语法。
    MongoDB 对投影实施了额外的限制。详情请见Projection Restrictions。


    你知道在 find 投影中使用聚合运算符在性能方面是更快还是更慢(或等于:))?

    根据find-projection-documentation,没有任何关于性能的规范,但我认为两者是相等的。

    如果你真的想检查这两种方法的性能,那么你可以通过explain() executionStats 模式检查。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-10
      • 2020-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-04
      相关资源
      最近更新 更多