【问题标题】:How to sort by the difference in array contents in mongodb?如何按MongoDB中数组内容的差异排序?
【发布时间】:2016-08-26 04:36:49
【问题描述】:

假设我的收藏中有以下文档:

var data = [
         { myArray: [ { a:1 }, { a:45 }, { a:46 } ] },
         { myArray: [ { a:3 } ] },
         { myArray: [ { a:12 }, { a:3 } ] },
         { myArray: [ { a:14 }, { a:33 }, { a:66 } ] }
     ]

我想根据“myArray”中最后两个“a”值的差异对它们进行排序。

所以算法应该是:

1) 拒绝 myArray 长度 的任何文档

var result = [
         { myArray: [ { a:1 }, { a:45 }, { a:46 } ] },
         { myArray: [ { a:12 }, { a:3 } ] },
         { myArray: [ { a:14 }, { a:33 }, { a:66 } ] }
     ]

2) 找出最后两个“a”值的差异

var result = [
         { myArray: [ { a:1 }, { a:45 }, { a:46 } ], diff: 1 },
         { myArray: [ { a:12 }, { a:3 } ], diff: -9 },
         { myArray: [ { a:14 }, { a:33 }, { a:66 } ], diff: 33 }
     ]

3) 按“差异”排序

var result = [
         { myArray: [ { a:14 }, { a:33 }, { a:66 } ], diff: 33 },
         { myArray: [ { a:1 }, { a:45 }, { a:46 } ], diff: 1 },
         { myArray: [ { a:12 }, { a:3 } ], diff: -9 }             
     ]

4) 返回结果

【问题讨论】:

    标签: javascript mongodb sorting mongodb-query aggregation-framework


    【解决方案1】:

    如果您的 MongoDB 服务器版本是 3.2 或更高版本,最好的方法是使用 .aggregate()。管道的第一阶段是使用$match 聚合管道运算符过滤掉所有“myArray”长度小于2 的文档。此操作还减少了要在管道中处理的文档数量。下一阶段是$project 阶段,您使用$arrayElemAt 运算符返回指定索引处的元素,这里数组中的最后两个元素使用索引-1 和索引-2。当然,这里的$let 运算符用于将这些值分配给一个变量,然后在$subtract 表达式中使用这些变量来返回差异。最后一个阶段是 $sort 聚合管道阶段,您可以在其中对文档进行排序。

    db.collection.aggregate([ 
        { "$match": { "myArray.1": { "$exists": true } } }, 
        { "$project": { 
            "myArray": "$myArray", 
            "diff": { 
                "$let": { 
                    "vars": { 
                        "first": { "$arrayElemAt": [ "$myArray", -2 ] }, 
                        "last": { "$arrayElemAt": [ "$myArray", -1 ] } 
                    }, 
                    "in": { "$subtract": [ "$$last.a", "$$first.a" ] } 
                } 
            } 
        }}, 
        { "$sort": { "diff": -1 } }
    ])
    

    这会产生这样的结果:

    { "myArray" : [ { "a" : 14 }, { "a" : 33 }, { "a" : 66 } ], "diff" : 33 }
    { "myArray" : [ { "a" : 1 }, { "a" : 45 }, { "a" : 46 } ], "diff" : 1 }
    { "myArray" : [ { "a" : 12 }, { "a" : 3 } ], "diff" : -9 }
    

    我不认为有办法做到这一点,但你总是可以使用 Array.sort 来做这个客户端

    db.collection.find({ "myArray.1": { "$exists": true } }).toArray().sort(
        function(a, b) { 
            return a === b ? 0 :( a < b ? -1 : 1 ); 
        }
    )
    

    这将返回与使用聚合框架的查询相同的结果,只是“diff”字段不存在。另外值得一提的是,聚合解决方案比这快得多。

    【讨论】:

    • 假设我只运行不支持 $arrayElemAt 的 v3.0 (mlab) 是否有解决方法?
    • @mikeysee 在这种情况下,您需要在客户端执行此操作。如最后一个代码块所示。
    猜你喜欢
    • 2022-12-16
    • 1970-01-01
    • 2011-10-24
    • 2013-03-01
    • 1970-01-01
    • 2013-09-18
    • 1970-01-01
    • 1970-01-01
    • 2018-07-28
    相关资源
    最近更新 更多