按Mongodb中的嵌入对象值排序

时间:2015-11-08 08:47:39

标签: mongodb mongodb-query aggregation-framework

我有这样的架构:

{
   tags:[
      {
         id:"t1",
         score:70
      },
      {
         id:"t1",
         score:60
      }
   ]
 }

我想对tag.id搜索的查询进行排序,以便按相应的分数排序。因此,如果我搜索db.collection.find({tags.id:" t1"})。sort({tags.score:-1}),它按" t1&#的得分排序34;对象不是其他标签。

有什么建议吗?

2 个答案:

答案 0 :(得分:1)

如果你需要在运行时计算这样的东西,使用数组中的“过滤”内容来确定排序顺序,那么你最好用.aggregate()做一些重构并确定这样的排序值:< / p>

db.collection.aggregate([
    // Pre-filter the array elements
    { "$project": {
        "tags": 1,
        "score": {
            "$setDifference": [
                { "$map": {
                    "input": "$tags",
                    "as": "tag",
                    "in": {
                        "$cond": [
                            { "$eq": [ "$$el.id", "t1" ] },
                            "$$el.score",
                            false
                        ]
                    }
                }},
                [false]
            ]
        }
    }},
    // Unwind to denormalize
    { "$unwind": "$score" },
    // Group back the "max" score
    { "$group": {
        "_id": "$_id",
        "tags": { "$first": "$tags" },
        "score": { "$max": "$score" }
    }},
    // Sort descending by score
    { "$sort": { "score": -1 } }
])

管道的第一部分用于“预过滤”数组内容(以及保持原始字段)仅为“得分”的值,其中id等于“t1”。这是通过处理$map来完成的,$cond通过$setDifference将条件应用于每个元素,以确定是否返回该元素的“得分”或false

$unwind操作与单个元素数组[false]进行比较,有效删除false返回的所有$map值。作为“集合”,这也会删除重复的条目,但为了排序目的,这是一件好事。

将数组缩小并重新整形为值,您可以处理$group,为下一个阶段处理作为单个元素的值。 $max阶段基本上在“得分”上应用$sort以返回过滤结果中包含的最高值。

然后,只需在确定的值上应用$min来订购文档。自然如果你想要反过来那么使用$match并按升序排序。

当然,如果你真正想要的是在标签中实际包含id的“t1”值的文档,那么在开头添加一个$max阶段。但是,这部分与您希望实现的过滤结果的排序最不相关。

计算的替代方法是在向文档中的数组写入条目时执行所有操作。有点乱,但它是这样的:

db.collection.update(
    { "_id": docId },
    {
        "$push": { "tags": { "id": "t1", "score": 60 } },
        "$max": { "maxt1score": 60 },
        "$min": { "mint1score": 60 }
    }
)

此处$min更新运算符仅在新值大于现有值或者尚不存在属性时才设置指定字段的值。相反的情况适用于{{3}},其中只有少于它将被替换为新值。

这当然可以为文档添加各种附加属性,但最终结果是大大简化了排序:

db.collection.find().sort({ "maxt1score": -1 })

它的运行速度比使用聚合管道计算要快得多。

因此,请考虑设计原则。数组中的结构化数据,您希望筛选和配对结果进行排序,这意味着在运行时计算以确定要排序的值。在.update()上向文档添加其他属性意味着您可以简单地引用这些属性以直接对结果进行排序。

答案 1 :(得分:0)

根据上述描述查询

$ groff -T ascii spaces.tr  |sed -n -e/./p
This is line 1. This is line 2.
This is line 1.  This is line 2.
This is line 1.  This is line 2.
SET SENTENCE SPACING
This is line 1. This is line 2.
This is line 1. This is line 2.
This is line 1. This is line 2.

将过滤由标签ID 1组成的文档,并将按降序排列按结果排序的结果。

另外,请提供详细说明以及示例文档和预期输出结果