【问题标题】:MongoDB Aggregation with DBRef使用 DBRef 进行 MongoDB 聚合
【发布时间】:2015-07-08 17:06:53
【问题描述】:

是否可以聚合通过 DBRef 存储的数据?

Mongo 2.6

假设我有如下交易数据:

{
  _id : ObjectId(...),
  user : DBRef("user", ObjectId(...)),
  product : DBRef("product", ObjectId(...)),
  source : DBRef("website", ObjectId(...)),
  quantity : 3,
  price : 40.95,
  total_price : 122.85,
  sold_at : ISODate("2015-07-08T09:09:40.262-0700")
}

诀窍是“source”本质上是多态的——它可能是不同的 $ref 值,例如“webpage”、“call_center”等,它们也有不同的 ObjectId。例如 DBRef("webpage", ObjectId("1")) 和 DBRef("webpage",ObjectId("2")) 将是交易发起的两个不同网页。

我想最终在一段时间内(比如一个月)按来源汇总:

db.coll.aggregate( { $match : { sold_at : { $gte : start, $lt : end } } },
                   { $project : { source : 1, total_price : 1 } },
                   { $group : { 
                         _id : { "source.$ref" : "$source.$ref" },
                         count : { $sum : $total_price }
                      } } );

诀窍是您尝试使用以 $ 开头的变量时会遇到路径错误,方法是尝试按其分组或尝试通过项目使用表达式进行转换。

有什么办法吗?实际上试图通过聚合将这些数据推送到子集合以在那里对其进行操作。试图避免对数百万条记录进行大型游标操作来转换数据,以便我可以聚合它。

【问题讨论】:

    标签: mongodb aggregation-framework dbref


    【解决方案1】:

    Mongo 4. 通过以下方式解决了这个问题: 具有这种结构:

    {
        "_id" : LUUID("144e690f-9613-897c-9eab-913933bed9a7"),
        "owner" : {
            "$ref" : "person",
            "$id" : NumberLong(10)
        },
        ...
        ...
    }
    

    我需要使用“owner.$id”字段。但是由于字段名称中的“$”,我无法使用聚合。 我使用以下 sn-p 转换了“owner.$id”->“owner”:

    db.activities.find({}).aggregate([
        {
            $addFields: {
                "owner": {
                    $arrayElemAt: [{ $objectToArray: "$owner" }, 1]
                }
            }   
        },
        {
            $addFields: {
                "owner": "$owner.v"
            }
        },
        {"$group" : {_id:"$owner", count:{$sum:1}}},
        {$sort:{"count":-1}}
    ])
    

    这里有详细解释-https://dev.to/saurabh73/mongodb-using-aggregation-pipeline-to-extract-dbref-using-lookup-operator-4ekl

    【讨论】:

      【解决方案2】:

      您不能将DBRef 值与聚合框架一起使用。相反,您需要使用 mapReduce 的 JavaScript 处理来访问他们使用的属性命名:

      db.coll.mapReduce(
          function() {
              emit( this.source.$ref, this["total_price"] )
          },
          function(key,values) {
              return Array.sum( values );
          },
          {
              "query": { "sold_at": { "$gte": start, "$lt": end } },
              "out": { "inline": 1 }
          }
      )
      

      你真的不应该使用DBRef。现在基本上不推荐使用这种用法,如果您觉得需要一些外部引用,那么您应该使用自己的代码“手动引用”它或由其他库实现,您可以通过更受支持的方式这样做。

      【讨论】:

      • 谢谢,和我想的差不多。我有一种方法可以通过批量聚合“展平”来解决这个问题,这比通过游标一个接一个地做得更好。不幸的是,在我们完善的代码库中不使用 DBRef 说起来容易做起来难 :-)
      猜你喜欢
      • 2021-04-03
      • 2021-04-20
      • 1970-01-01
      • 2021-11-28
      • 1970-01-01
      • 2015-08-01
      • 2019-06-29
      • 2019-02-03
      • 2017-02-16
      相关资源
      最近更新 更多