【问题标题】:MongoDB: Project to array item with minimum value of fieldMongoDB:项目到具有最小值字段的数组项
【发布时间】:2017-04-12 08:49:01
【问题描述】:

假设我的收藏包含如下所示的项目:

{
    "items" : [
        {
            "item_id": 1,
            "item_field": 10
        },
        {
            "item_id": 2,
            "item_field": 15
        },
        {
            "item_id": 3,
            "item_field": 3
        },
    ]
}

我能否以某种方式选择具有最小值item_fielditems 条目,在本例中为item_id 3 的条目?

我可以使用聚合框架。如果您能给我 C# 驱动程序的代码,则加分。

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework mongodb-.net-driver


    【解决方案1】:

    您可以通过以下方式使用$reduce 表达式。

    下面的查询会将initialValue 设置为$items.item_field 的第一个元素,然后将$ltitem_field 进行比较,如果为真,则将$$this 设置为$$value,如果为假,则保留以前的值和$reduce 找到最小元素的所有值,$project 输出最小项。

    db.collection.aggregate([
        {
             $project:  {
                items: {
                    $reduce: {
                        input: "$items",
                        initialValue:{ 
                             item_field:{ 
                                $let: { 
                                    vars: { obj: { $arrayElemAt: ["$items", 0] } },
                                    in: "$$obj.item_field"
                                }
                            }
                        },
                        in: {
                              $cond: [{ $lt: ["$$this.item_field", "$$value.item_field"] }, "$$this", "$$value" ] 
                        }
                    }
                }
            }
        }
    ])
    

    【讨论】:

    • 我认为这应该比unwind 解决方案更有效吗?
    • 节省空间。我认为对于较小的数据集来说这并不重要,但在较大的数据集中展开可能会更慢。您必须比较这两种解决方案的数据集时间效率。
    • 我的理解是,unwind 的解决方案还涉及 O(n * log g) 而reduce 是 O(n) 的排序。
    【解决方案2】:

    您可以使用$unwind 来分隔项目条目。 然后$sort by item_field asc 然后$group

    db.coll.find().pretty()
    {
        "_id" : ObjectId("58edec875748bae2cc391722"),
        "items" : [
            {
                "item_id" : 1,
                "item_field" : 10
            },
            {
                "item_id" : 2,
                "item_field" : 15
            },
            {
                "item_id" : 3,
                "item_field" : 3
            }
        ]
    }
    
    db.coll.aggregate([
      {$unwind: {path: '$items', includeArrayIndex: 'index'}}, 
      {$sort: { 'items.item_field': 1}},
      {$group: {_id: '$_id', item: {$first: '$items'}}} 
    ])
    { "_id" : ObjectId("58edec875748bae2cc391722"), "item" : { "item_id" : 3, "item_field" : 3 } }
    

    【讨论】:

    • 您能描述一下如何使用 C# 驱动程序来实现吗?
    • 对不起,我不懂 C#。根据official doc,它应该看起来像:var aggregate = collection.Aggregate() .Unwind(new BsonDocument { { "path", "$items" } }) .Sort(new BsonDocument { { "items.item_field", 1 } }) .Group(new BsonDocument { { "_id", "$_id" }, { "item", new BsonDocument("$first", "$items") } }); var results = await aggregate.ToListAsync();
    【解决方案3】:

    我们可以使用以下查询得到预期的结果

    db.testing.aggregate([{$unwind:"$items"}, {$sort: { 'items.item_field': 1}},{$group: {_id: "$_id", minItem: {$first: '$items'}}}])
    

    结果是

    { "_id" : ObjectId("58edf28c73fed29f4b741731"), "minItem" : { "item_id" : 3, "item_field" : 3 } }
    { "_id" : ObjectId("58edec3373fed29f4b741730"), "minItem" : { "item_id" : 3, "item_field" : 3 } }
    

    【讨论】:

    • 这给了我一个结果。如果我想获取集合中每个文档的最小项怎么办?
    • 我刚刚偶然发现了$reduce 运算符。是否可以在$project 步骤中使用以获取最小数组项?
    • 您能描述一下如何使用 C# 驱动程序来实现吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-10
    • 1970-01-01
    • 2023-04-11
    • 1970-01-01
    • 2018-05-22
    • 1970-01-01
    相关资源
    最近更新 更多