MongoDB聚合与DBRef

5

能否对通过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”等,这些值也具有不同的ObjectIds。例如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 }
                      } } );

技巧是,如果您尝试使用以 $ 开头的变量进行分组或尝试通过项目使用表达式进行转换,则会出现路径错误。

有没有什么办法可以解决这个问题?实际上,我正在尝试通过聚合将此数据推送到子集合中,在那里对其进行操作。试图避免对数百万条记录进行大规模游标操作,以便我可以对其进行聚合。

2个回答

2
Mongo 4解决了以下问题: 采用以下结构:
{
    "_id" : LUUID("144e690f-9613-897c-9eab-913933bed9a7"),
    "owner" : {
        "$ref" : "person",
        "$id" : NumberLong(10)
    },
    ...
    ...
}

我需要使用"owner.$id"字段,但是由于字段名中含有"$"符号,我无法使用聚合功能。我使用以下代码将"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

(本文主要介绍如何使用聚合管道和查找操作符提取DBRef)

1

您不能在聚合框架中使用DBRef值。相反,您需要使用mapReduce的JavasScript处理方式以访问它们所使用的属性命名:

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并不容易实现。 - Jeff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接