【问题标题】:how to sort before querying in the embedded document嵌入文档中查询前如何排序
【发布时间】:2015-01-18 13:15:25
【问题描述】:

我知道如何在查找结果之后对嵌入文档进行排序,但是如何在查找之前进行排序以便查询本身在排序后的数组上运行?我知道如果我使用聚合,这一定是可能的,但我真的很想知道没有它是否可行,以便我更好地理解它是如何工作的。

这是我的嵌入文档

   "shipping_charges" : [
            {
                    "region" : "region1",
                    "weight" : 500,
                    "rate" : 10
            },
            {
                    "region" : "Bangalore HQ",
                    "weight" : 200,
                    "rate" : 40
            },
            {
                    "region" : "region2",
                    "weight" : 1500,
                    "rate" : 110
            },
            {
                    "region" : "region3",
                    "weight" : 100,
                    "rate" : 50
            },
            {
                    "region" : "Bangalore HQ",
                    "weight" : 100,
                    "rate" : 150
            }
    ]

这是我用来匹配“区域”和“权重”的查询,以获取该匹配项的定价..

db.clients.find( { "shipping_charges.region" : "Bangalore HQ" ,  "shipping_charges.weight" : { $gte : 99 }  }, { "shipping_charges.$" : 1 }  ).pretty()

这个查询当前返回给我

     {
    "shipping_charges" : [
            {
                    "region" : "Bangalore HQ",
                    "weight" : 200,
                    "rate" : 40
            }
    ]

}

它可能返回这个集合的原因是因为它在嵌入文档中出现(和匹配)的顺序。

但是,我希望这能将最后一组最匹配最接近重量的平板(100 克)返回给我

我的现有查询需要进行哪些更改,以便我可以在查找运行之前对嵌入文档进行排序以获得我想要的结果?

如果出于任何原因您确定没有 MPR 就无法完成,请告诉我,这样我就可以远离这种方法,只专注于 MPR 以获得所需的结果。

【问题讨论】:

    标签: mongodb mongodb-query


    【解决方案1】:

    您可以使用聚合管道代替 map-reduce:

    db.clients.aggregate([
        // Filter the docs to what we're looking for.
        {$match: {
            'shipping_charges.region': 'Bangalore HQ',
            'shipping_charges.weight': {$gte: 99}
        }},
    
        // Duplicate the docs, once per shipping_charges element
        {$unwind: '$shipping_charges'},
    
        // Filter again to get the candidate shipping_charges.
        {$match: {
            'shipping_charges.region': 'Bangalore HQ',
            'shipping_charges.weight': {$gte: 99}
        }},
    
        // Sort those by weight, ascending.
        {$sort: {'shipping_charges.weight': 1}},
    
        // Regroup and take the first shipping_charge which will be the one closest to 99
        // because of the sort.        
        {$group: {_id: '$_id', shipping_charges: {$first: '$shipping_charges'}}}
    ])
    

    您也可以使用find,但您需要在文档本身中按weightshipping_charges 数组进行预排序。您可以通过使用带有$sort 修饰符的$push 更新来做到这一点:

    db.clients.update({}, {
        $push: {shipping_charges: {$each: [], $sort: {weight: 1}}}
    }, {multi: true})
    

    这样做之后,您现有的查询将返回正确的元素:

    db.clients.find({ 
        "shipping_charges.region" : "Bangalore HQ",
        "shipping_charges.weight" : { $gte : 99 }
    }, { "shipping_charges.$" : 1 } )
    

    当然,您需要在对文档的 shipping_charges 数组的任何进一步更新中始终包含 $sort 修饰符,以确保其保持排序。

    【讨论】:

    • 谢谢,Johnny HK。抱歉,我的意思是“聚合”方法而不是 MPR。所以,你认为没有聚合是不可能的,认为我的要求只是在“查找”实际在数组上运行之前有一个额外的“权重”排序方法?
    • @Param 我已经更新了我的答案,包括了一种使用find 的方法。
    • 如果我们重新排序 shipping_charges 的项目,find() 结果会有所不同(我测试过),但聚合效果很好 +1
    • 我认为,如果我可以在将它们全部插入我的收藏之前进行预排序,这样它将始终保持排序,因为不允许编辑此收藏,但可以删除以确保它将以我插入收藏的方式。但是,当我尝试对它们进行预排序时,它会说“切片”是预期的。就像错误“没有 $slice 就不能有 $sort”
    • @Param 我猜你使用的是 MongoDB 2.4.x?在 2.6+ 中,您现在可以在没有 $slice 的情况下使用 $sort。
    猜你喜欢
    • 2021-02-21
    • 1970-01-01
    • 2012-03-10
    • 2012-08-22
    • 1970-01-01
    • 2015-04-23
    • 1970-01-01
    • 2012-08-26
    • 1970-01-01
    相关资源
    最近更新 更多