简体   繁体   English

如何按加权值排序

[英]How to Sort by Weighted Values

I have this problem that I want to sort the result of a query based on the field values from another collection, 我有一个问题,我想根据另一个集合的字段值对查询结果进行排序,

Problem: I want to first get the user 123 friends and then get their posts and then sort the post with the friends strength value, 问题:我想首先让用户获得123个朋友,然后获取他们的帖子,然后使用朋友的强度值对帖子进行排序,

I have this : 我有这个 :

POST COLLECTON:
{
    user_id: 8976,
    post_text: 'example working',
}
{
    user_id: 673,
    post_text: 'something',
}

USER COLLECTON:
{
    user_id: 123,
    friends: {
        {user_id: 673,strength:4}
        {user_id: 8976,strength:1}
    }
}

Based on the information you have retrieved from your user you essentially want to come out to an aggregation framework query that looks like this: 根据您从用户中检索到的信息,您实际上希望进行如下所示的聚合框架查询:

db.posts.aggregate([
    { "$match": { "user_id": { "$in": [ 673, 8976 ] } } },
    { "$project": {
        "user_id": 1,
        "post_text": 1,
        "weight": {
            "$cond": [
                { "$eq": [ "$user_id", 8976 ] },
                1,
                { "$cond": [ 
                    { "$eq": [ "$user_id", 673 ] },
                    4,
                    0
                ]}
            ]
        }
    }},
    { "$sort": { "weight": -1 } }
])

So why aggregation when this does not aggregate? 那么为什么不聚合就聚合呢? As you can see, the aggregation framework does more than just aggregate. 如您所见,聚合框架所做的不仅仅是聚合。 Here it is being used to "project" a new field into the document an populate it with a "weight" to sort on. 在这里,它用于将新字段“投影”到文档中,并用“权重”进行填充。 This allows you to get the results back ordered by the value you want them to be sorted on. 这使您可以按希望排序结果的值将结果重新排序。

Of course, you need to get from your initial data to this form in a "generated" way that you do do for any data. 当然,您需要以一种对所有数据所做的“生成的”方式,将初始数据从原始数据转换为该表单。 This takes a few steps, but here I'll present the JavaScript way to do it, which should be easy to convert to most languages 这需要几个步骤,但是在这里,我将介绍实现它的JavaScript方法,该方法应该很容易转换为大多数语言

Also presuming your actual "user" looks more like this, which would be valid: 还要假设您的实际“用户”看起来更像这样,这将是有效的:

{
    "user_id": 123,
    "friends": [
        { "user_id": 673,  "strength": 4 },
        { "user_id": 8976, "strength": 1 }
    ]
}

From an object like this you then construct the aggregation pipeline: 从这样的对象中,然后构造聚合管道:

// user is the structure shown above

var stack = [];
args = [];

user.friends.forEach(function(friend) {

    args.push( friend.user_id );

    var rec = {
        "$cond": [
            { "$eq": [ "user_id", friend.user_id ] },
            friend.strength
        ]
    };

    if ( stack.length == 0 ) {
        rec["$cond"].push(0);
    } else {
        var last = stack.pop();
        rec["$cond"].push( last );
    }

    stack.push( rec );

});


var pipeline = [
    { "$match": { "user_id": { "$in": args } } },
    { "$project": {
        "user_id": 1,
        "post_text": 1,
        "weight": stack[0]
    }},
    { "$sort": { "weight": -1 } }
];

db.posts.aggregate(pipeline);

And that is all there is to it. 这就是全部。 Now you have some code to go through the list of "friends" for a user and construct another query to get all posts from those friends weighted by the "strength" value for each. 现在,您有了一些代码,可以浏览用户的“朋友”列表,并构造另一个查询,以从每个朋友的“强度”值加权得到这些朋友的所有帖子。

Of course you could do much the same things with a query for all posts by just removing or changing the $match , but keeping the "weight" projection you can "float" all of the "friends" posts to the top. 当然,通过删除或更改$match ,您可以通过查询所有帖子来做几乎相同的事情,但是保持“权重”投射可以将所有“朋友”帖子“浮动”到顶部。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM