【问题标题】:Relate children to parent using Mongo aggregate query使用 Mongo 聚合查询将子级与父级关联
【发布时间】:2016-05-02 20:33:45
【问题描述】:

我有一个名为 assets 的集合,其中包含 2 种以上格式的文档,ParentObject 和 ChildObject。我目前正在通过两个查询将 ParentObject 与 ChildObject 相关联。这可以通过聚合查询来完成吗?

父对象

{
    "_id" : {
        "oid" : "ParentFooABC",
        "brand" : "acme"
    },
    "type": "com.ParentClass",
    "title": "Title1234",

    "availableDate": Date,
    "expirationDate": Date
}

子对象

{
    "_id" : {
        "oid" : "ChildFoo",
        "brand" : "acme"
    },
    "type": "com.ChildClass",
    "parentObject": "ParentFooABC",
    "title": "Title1234",
    "modelNumber": "8HE56",
    "modelLine": "Metro",
    "availableDate": Date,
    "expirationDate": Date,
    "IDRequired": true
}

目前我像这样过滤数据

val parent = db.asset.find(MongoDBObject("_id.brand": MongoDBObject($eq: "acme")),MongoDBObject("type":"com.ParentClass"))
val children = db.asset.find(MongoDBObject("_id.brand": MongoDBObject($eq: "acme")),MongoDBObject("type":"com.ChildClass"), MongoDBObject("parentObject": "${parent._id.oid}"))
if(childs.nonEmpty) {
  //I have confirmed this parent has a child associated and should be returned
  val childModelNumbers = childs.map(child -> child.modelNumber)
  val response = ResponseObject(parent, childModelNumbers)
}

我可以在聚合查询中执行此操作吗?

更新

Mongo 版本:db 版本 v2.6.11

语言:斯卡拉

驱动程序:Casbah 2.8.1

【问题讨论】:

    标签: mongodb scala casbah


    【解决方案1】:

    技术上是的,但是您现在正在做的是 mongodb 的标准做法。如果您需要经常加入数据集合,您可能应该使用 RDBMS。但是,如果您偶尔需要从 2 个单独的集合中聚合数据,则可以使用 $lookup。通常,您会发现自己非常频繁地将数据从另一个文档填充到您的文档中,但这通常是文档数据库的工作方式。当您真的在寻找与 SQL JOIN 等效的对象时,我不建议您使用 $lookup。这不是真正的预期目的,您最好完全按照您现在正在做的事情或迁移到 RDBMS。

    补充:

    由于数据在同一个集合中,您可以使用聚合到$group 该数据一起。您只需根据_id.brand 对它们进行分组。

    一个简单的例子(在 mongodb shell 中):

    db.asset.aggregate([
    {  //start with a match to narrow down
       $match: {"_id.brand": "acme"}
    },
    { //group by `_id.brand`
       $group: {
          _id: "$_id.brand",
          "parentObject": {$first: "$parentObject"},
          title: {$first: "$title"},
          modelNumer: {$addToSet: "$modelNumer"}, //accumulate child model # as array
          modelLine: {$addToSet: "$modelLine"}, //accumulate child model line as array
          availableDate: {$first: "$availableDate"},
          expirationDate: {$first: "$expirationDate"}
       }
    }
    ]);
    

    这应该返回所有子属性已作为数组(modelNumber,modelLine)分组到父文档中的文档。执行上面的操作可能会更好,如果您将孩子放入他们自己的集合中,而不是在文档中使用 type 字段跟踪他们的 type 可能会更好.这样你就知道每个集合中的文档代表一个给定的数据结构。但是,如果您这样做,您将无法执行示例中的聚合。

    【讨论】:

    • 感谢您的快速回复!我犯了一个错误,因为我最初没有包含我的 Mongo 版本号,并且我无法使用 $lookup Mongo 2.6 doc。虽然看起来我正在执行连接,但 ParentObject 和 ChildObject 实际上都在同一个集合中。我希望用 $match 获取所有文档,然后在同一个聚合管道中比较它们
    • @KevinHarper 是的,这是最近添加的。通常,您会将父项和子项放在不同的集合中,将 id 作为引用存储在子项或父文档中,然后根据父项的 id 查询子项或基于存储在父项中的子项 id 数组进行查询.我完全错过了您将它们都放在同一个系列中的观点。但是,您可能可以通过 _id.brand $group 并使用当前方法从每个文档中获取您需要的任何数据。
    • @KevinHarper 你应该更新你的问题,我会更新我的答案以匹配它。您使用什么语言?在您的问题上标记它可能会有所帮助。
    • 很好的建议。我已经用 Mongo 版本、语言 (Scala) 和驱动程序 (Casbah) 更新了我的问题
    • @KevinHarper 我没有使用 casbah 的经验,但是我可以提供一些示例作为 mongodb 查询,而不是使用 casbah DSL 格式化。这可以接受吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-26
    • 1970-01-01
    • 1970-01-01
    • 2015-02-15
    • 1970-01-01
    • 2017-08-12
    • 2015-11-28
    相关资源
    最近更新 更多