代码之家  ›  专栏  ›  技术社区  ›  Punit

如何在mongoDB中编写联合查询

  •  8
  • Punit  · 技术社区  · 7 年前

    是否可以使用2个或更多类似于SQL查询的集合在Mongo DB中编写联合查询?

    例如,我有一个名为“circuitId”的字段,它出现在所有4个集合中。我需要从该字段与给定值匹配的所有4个集合中获取所有记录。

    3 回复  |  直到 4 年前
        1
  •  19
  •   sboisse    5 年前

    在MongoDB中以“SQL联合”的方式进行联合是可能的,可以在单个查询中使用聚合和查找。

        db.getCollection("AnyCollectionThatContainsAtLeastOneDocument").aggregate(
        [
          { $limit: 1 }, // Reduce the result set to a single document.
          { $project: { _id: 1 } }, // Strip all fields except the Id.
          { $project: { _id: 0 } }, // Strip the id. The document is now empty.
    
          // Lookup all collections to union together.
          { $lookup: { from: 'collectionToUnion1', pipeline: [...], as: 'Collection1' } },
          { $lookup: { from: 'collectionToUnion2', pipeline: [...], as: 'Collection2' } },
          { $lookup: { from: 'collectionToUnion3', pipeline: [...], as: 'Collection3' } },
    
          // Merge the collections together.
          {
            $project:
            {
              Union: { $concatArrays: ["$Collection1", "$Collection2", "$Collection3"] }
            }
          },
    
          { $unwind: "$Union" }, // Unwind the union collection into a result set.
          { $replaceRoot: { newRoot: "$Union" } } // Replace the root to cleanup the resulting documents.
        ]);
    

    以下是其工作原理的说明:

    1. 实例化 aggregate 从…里面 任何 数据库的集合,其中至少有一个文档。如果不能保证数据库的任何集合都不会为空,可以通过在数据库中创建某种“虚拟”集合来解决此问题,该集合中包含一个空文档,专门用于执行联合查询。

    2. { $limit: 1 } . 这将删除收藏中除第一个文件外的所有文件。

    3. 使用删除剩余文档的所有字段 $project

      { $project: { _id: 1 } },
      { $project: { _id: 0 } }
      
    4. 您的聚合现在包含单个空文档。是时候为每个要合并在一起的集合添加查找了。您可以使用 pipeline 字段来做一些特定的过滤,或者离开 localField foreignField

      { $lookup: { from: 'collectionToUnion1', pipeline: [...], as: 'Collection1' } },
      { $lookup: { from: 'collectionToUnion2', pipeline: [...], as: 'Collection2' } },
      { $lookup: { from: 'collectionToUnion3', pipeline: [...], as: 'Collection3' } }
      
    5. 现在,您有了一个包含单个文档的聚合,该文档包含以下3个数组:

      {
          Collection1: [...],
          Collection2: [...],
          Collection3: [...]
      }
      

      $项目 舞台与 $concatArrays 聚合运算符:

      {
        "$project" :
        {
          "Union" : { $concatArrays: ["$Collection1", "$Collection2", "$Collection3"] }
        }
      }
      
    6. $unwind 和a $replaceRoot 将阵列拆分为单独文档的阶段:

      { $unwind: "$Union" },
      { $replaceRoot: { newRoot: "$Union" } }
      
        2
  •  10
  •   Xavier Guihot    4 年前

    启动 Mongo 4.4 $unionWith 阶段,执行两个集合的并集(组合管道将两个集合的结果合并到单个结果集中)。

    // > db.collection1.find()
    //   { "circuitId" : 12, "a" : "1" }
    //   { "circuitId" : 17, "a" : "2" }
    //   { "circuitId" : 12, "a" : "5" }
    // > db.collection2.find()
    //   { "circuitId" : 12, "b" : "x" }
    //   { "circuitId" : 12, "b" : "y" }
    // > db.collection3.find()
    //   { "circuitId" : 12, "c" : "i" }
    //   { "circuitId" : 32, "c" : "j" }
    db.collection1.aggregate([
      { $match: { circuitId: 12 } },
      { $unionWith: { coll: "collection2", pipeline: [{ $match: { circuitId: 12 } }] } },
      { $unionWith: { coll: "collection3", pipeline: [{ $match: { circuitId: 12 } }] } }
    ])
    // { "circuitId" : 12, "a" : "1" }
    // { "circuitId" : 12, "a" : "5" }
    // { "circuitId" : 12, "b" : "x" }
    // { "circuitId" : 12, "b" : "y" }
    // { "circuitId" : 12, "c" : "i" }
    

    这:

    • 首先从中筛选文档 collection1
    • 然后包括来自 collection2 与新的 阶段这个 pipeline 参数是一个可选的聚合管道,在合并之前应用于正在合并的集合中的文档。
    • 还包括来自 collection3 $unionWith 阶段
        3
  •  1
  •   Pubudu Jayawardana    7 年前

    不幸的是,基于文档的MongoDB不支持关系数据库引擎中的连接/联合。 话虽如此,如果您真的需要使用这4个集合,您将需要管理应用程序端的逻辑,或者您可以根据MongoDB最佳实践重新设计DB设计。

    更多信息: https://docs.mongodb.com/master/core/data-model-design/