如何在Meteor(MongoDB)中使用复杂函数对集合进行排序

时间:2015-10-13 13:34:07

标签: mongodb sorting meteor

我有复杂的公式p / a^5我想要对一个集合进行排序,其中pa是集合Items的属性。

在Meteor(MongoDB)中有没有办法做到这一点?

3 个答案:

答案 0 :(得分:1)

不,你不能这样做。我建议添加另一个存储p / a^5值的字段。例如。假设您将此字段称为pResult,那么您可以这样做:

collection.find(selector, {sort: {pResult: 1}});

答案 1 :(得分:0)

您只需fetch()该集合,然后使用常规Array.prototype.sort_.sortBy进行排序。但是,这会破坏细粒度的反应性,因此如果您的集合很大或者渲染的元素足够复杂,并且集合会随着时间的推移而发生很大变化,那么您可能会遇到性能问题。

Template.whatever.helpers({
    items: function () {
        return _.sortBy(Items.find().fetch(), function (item) {
            return item.p / Math.pow(item.a, 5);
        });
    }
});
<template name="whatever">
    {{#each items}}
        <!-- ... -->
    {{/each}}
</template>

如果您需要细粒度的反应性,您可以查看我的包collection-view,但我不认为它已准备就绪。

答案 2 :(得分:0)

您可以使用 aggregation framework 。您可以构建聚合管道,以便它通过使用算术运算符 $multiply 执行指数函数,将n称为n指数的次数r

例如,以下聚合管道将添加一个额外的字段p / a^5,这是操作exponents的结果。

首先,在mongo shell中,在for(x=0; x < 10; x++){ db.exponents.insert({p: 5*x, a: x }); } 集合中创建一些示例文档:

var pipeline = [
    {
        "$match" : {
            "a" : {
                "$gt" : 0
            }
        }
    },
    {
        "$project" : {
            "p" : 1,
            "a" : 1,
            "r" : {
                "$divide" : [
                    "$p",
                    {
                        "$multiply" : [
                            "$a",
                            "$a",
                            "$a",
                            "$a",
                            "$a"
                        ]
                    }
                ]
            }
        }
    },
    {
        "$sort" : {
            "r" : 1
        }
    }
];

生成管道:

db.exponents.aggregate(pipeline);

使用上面的示例文档运行管道:

/* 0 */
{
    "result" : [ 
        {
            "_id" : ObjectId("561d1ced3d8f561c1548d393"),
            "p" : 45,
            "a" : 9,
            "r" : 0.0007620789513793629
        }, 
        {
            "_id" : ObjectId("561d1ced3d8f561c1548d392"),
            "p" : 40,
            "a" : 8,
            "r" : 0.001220703125
        }, 
        {
            "_id" : ObjectId("561d1ced3d8f561c1548d391"),
            "p" : 35,
            "a" : 7,
            "r" : 0.002082465639316951
        }, 
        {
            "_id" : ObjectId("561d1ced3d8f561c1548d390"),
            "p" : 30,
            "a" : 6,
            "r" : 0.003858024691358025
        }, 
        {
            "_id" : ObjectId("561d1ced3d8f561c1548d38f"),
            "p" : 25,
            "a" : 5,
            "r" : 0.008
        }, 
        {
            "_id" : ObjectId("561d1ced3d8f561c1548d38e"),
            "p" : 20,
            "a" : 4,
            "r" : 0.01953125
        }, 
        {
            "_id" : ObjectId("561d1ced3d8f561c1548d38d"),
            "p" : 15,
            "a" : 3,
            "r" : 0.06172839506172839
        }, 
        {
            "_id" : ObjectId("561d1ced3d8f561c1548d38c"),
            "p" : 10,
            "a" : 2,
            "r" : 0.3125
        }, 
        {
            "_id" : ObjectId("561d1ced3d8f561c1548d38b"),
            "p" : 5,
            "a" : 1,
            "r" : 5
        }
    ],
    "ok" : 1
}

<强>输出

.aggregate

您可以设置一个通用辅助函数来生成管道代码,以使用幂函数的文档表示中的算术运算符提取 $project 运算符。由于Meteor尚不支持聚合,请使用 meteorhacks:aggregate 包,为Meteor添加适当的聚合支持。此程序包在Mongo.Collection个实例上公开了meteor add meteorhacks:aggregate 方法。

使用

添加到您的应用中
.aggregate()

然后简单地使用.aggregate()函数和泛型函数来生成管道以用作下面的function power(exponent) { var multiply = []; for (var count = 0; count < exponent; count++){ multiply.push("$a"); } return [ { $match: { a: { $gt: 0} } }, { $project: { p: 1, a: 1, r : { $divide: [ "$p", { $multiply: multiply } ] } } }, { "$sort": { r: 1 } } ]; } var pipeline = power(5), exponents = new Mongo.Collection('exponents'), result = exponents.aggregate(pipeline); 参数:

STRING