1

I have two models, post and vote.

Post schema

title:{
    type: String,
    required: true,
},
description:{
    type: String,
    required: true,
},
votes: [
    {
        type: Schema.Types.ObjectId,
        ref: 'Vote'
    }
],

Vote Schema

const voteSchema = new Schema({
    post:{
        type: Schema.Types.ObjectId,
        ref: 'Post',
    },
    value:{
        type: Number,
        required: true,
    },
});

I am trying to sort post by the most value of votes grouped.

Maybe something like this?

var posts = Post.aggregate([{$sort: { $group: votes: {$sum: value} }}

Any help would be appreciated.

Thanks!

3 Answers 3

1

Since you're trying to $sort by an aggregated data from another collection, you need to use $lookup first in order to get total value from all related votes:

let posts = await Post.aggregate([
    {
        $lookup: {
            from: "votes",
            let: { post_votes: "$votes" },
            pipeline: [
                { $match: { $expr: { $in: [ "$_id", "$$post_votes" ] } } },
                { $group: { _id: null, total: { $sum: "$value" } }
            ],
            as: "votesTotalValue"
        }
    },
    { $unwind: "$votesTotalValue" },
    { $sort: { "votesTotalValue.total": -1 } }
])

Mongo Playground

Sign up to request clarification or add additional context in comments.

Comments

0

Inspired by this example on mongo's website.

 db.sales.insertMany([
  { "_id" : 1, "item" : "abc", "price" : NumberDecimal("10"), "quantity" : NumberInt("2"), "date" : ISODate("2014-03-01T08:00:00Z") },
 { "_id" : 2, "item" : "jkl", "price" : NumberDecimal("20"), "quantity" : NumberInt("1"), "date" : ISODate("2014-03-01T09:00:00Z") },
 { "_id" : 3, "item" : "xyz", "price" : NumberDecimal("5"), "quantity" : NumberInt( "10"), "date" : ISODate("2014-03-15T09:00:00Z") },
 { "_id" : 4, "item" : "xyz", "price" : NumberDecimal("5"), "quantity" :  NumberInt("20") , "date" : ISODate("2014-04-04T11:21:39.736Z") },
 { "_id" : 5, "item" : "abc", "price" : NumberDecimal("10"), "quantity" : NumberInt("10") , "date" : ISODate("2014-04-04T21:23:13.331Z") },
 { "_id" : 6, "item" : "def", "price" : NumberDecimal("7.5"), "quantity": NumberInt("5" ) , "date" : ISODate("2015-06-04T05:08:13Z") },
 { "_id" : 7, "item" : "def", "price" : NumberDecimal("7.5"), "quantity": NumberInt("10") , "date" : ISODate("2015-09-10T08:43:00Z") },
 { "_id" : 8, "item" : "abc", "price" : NumberDecimal("10"), "quantity" : NumberInt("5" ) , "date" : ISODate("2016-02-06T20:20:13Z") },
])

Group By Item Quantity and Sorting Items according to Quantity

db.sales.aggregate( [
{
$group: {
   _id: "$item",
   count: { $sum:"$quantity" }
  }
 }
],
{$sort:{"_id.quantity":1}} )

Output

{ 
"_id" : "jkl", 
"count" : NumberInt(1)
},
{ 
"_id" : "def", 
"count" : NumberInt(15)
},
{ 
"_id" : "abc", 
"count" : NumberInt(17)
},
{ 
"_id" : "xyz", 
"count" : NumberInt(30)
}

1 Comment

The OP wants to sort by a value that needs to be retrieved from another collection so $group is not enough to solve his problem
0

code sample for retrieving data from two collections with $lookup and sorting

// data preparation, please use drop command in your work with caution      
original_id = ObjectId();     
db.post.insertOne({"_id":original_id,title:"hotel review"});
db.vote.insertOne({post_id:original_id, vote:22});
//
original_id = ObjectId();     
db.post.insertOne({"_id":original_id,title:"movie review"});
db.vote.insertOne({post_id:original_id, vote:99});
//

> db.post.find();
{ "_id" : ObjectId("5f42573349cf5c81666018f5"), "title" : "hotel review" }
{ "_id" : ObjectId("5f42581949cf5c81666018f7"), "title" : "movie review" }
> db.vote.find();
{ "_id" : ObjectId("5f42573349cf5c81666018f6"), "post_id" : ObjectId("5f42573349cf5c81666018f5"), "vote" : 22 }
{ "_id" : ObjectId("5f42581949cf5c81666018f8"), "post_id" : ObjectId("5f42581949cf5c81666018f7"), "vote" : 99 }
> db.post.aggregate([ {$lookup:     {from:"vote",      localField:"_id",      foreignField:"post_id",      as:"post_docs"            }     }, {$sort:{"post_docs.vote":-1}} ]).pretty();
{
        "_id" : ObjectId("5f42581949cf5c81666018f7"),
        "title" : "movie review",
        "post_docs" : [
                {
                        "_id" : ObjectId("5f42581949cf5c81666018f8"),
                        "post_id" : ObjectId("5f42581949cf5c81666018f7"),
                        "vote" : 99
                }
        ]
}
{
        "_id" : ObjectId("5f42573349cf5c81666018f5"),
        "title" : "hotel review",
        "post_docs" : [
                {
                        "_id" : ObjectId("5f42573349cf5c81666018f6"),
                        "post_id" : ObjectId("5f42573349cf5c81666018f5"),
                        "vote" : 22
                }
        ]
}
> db.post.aggregate([ {$lookup:     {from:"vote",      localField:"_id",      foreignField:"post_id",      as:"post_docs"            }     }, {$sort:{"post_docs.vote":1}} ]).pretty();
{
        "_id" : ObjectId("5f42573349cf5c81666018f5"),
        "title" : "hotel review",
        "post_docs" : [
                {
                        "_id" : ObjectId("5f42573349cf5c81666018f6"),
                        "post_id" : ObjectId("5f42573349cf5c81666018f5"),
                        "vote" : 22
                }
        ]
}
{
        "_id" : ObjectId("5f42581949cf5c81666018f7"),
        "title" : "movie review",
        "post_docs" : [
                {
                        "_id" : ObjectId("5f42581949cf5c81666018f8"),
                        "post_id" : ObjectId("5f42581949cf5c81666018f7"),
                        "vote" : 99
                }
        ]
}
>

1 Comment

For the above-formatted code for aggregation for clarity.db.post.aggregate([ {$lookup: {from:"vote", localField:"_id", foreignField:"post_id", as:"post_docs" } }, {$sort:{"vote":-1}} ]).pretty();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.