如何在嵌入文档中查询之前进行排序

how to sort before querying in the embedded document

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

这是我的嵌入式文档

   "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
            }
    ]

这是我用来匹配 'region' 和 'weight' 以获取该匹配的定价的查询..

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

这个查询目前 return 是我

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

}

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

但是,我想让这个 return 我最后一组最适合最接近重量的平板(100 克)

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

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

您可以使用聚合管道代替 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})

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

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

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