Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
302 views
in Technique[技术] by (71.8m points)

mongodb - Sorting records in a way so that only records which matches an id comes first?

I have a query which return me the records or messages for a certain scenario:

const [messages, messageCount] = await Promise.all([
    MessageModel.find(params).select(filterObject).limit(ctx.query.limit).skip(ctx.paginate.skip)
      .sort('-sex -age')
      .lean(),
    MessageModel.countDocuments(params),
  ]);

Is there any way to get the records first which matches an object id, and then rest of the records?

Result

{
_id:abc0aa8573bfa917b152cdbc
isPrivate:false
message:"My name is stark"
gender:"unisex"
age: "19"
createdBy:abcff9ef71fa048cea3c8a97
}
{
_id:abc0aa8573bfa917b152cdbc
isPrivate:false
message:"My name is james"
gender:"unisex"
age: "20"
createdBy:defff9ef71fa048cea3c8a97
}
{
_id:abc0aa8573bfa917b152cdbc
isPrivate:false
message:"My name is harry"
gender:"unisex"
age: "20"
createdBy:defff9ef71fa048cea3c8a97
}
{
_id:abc0aa8573bfa917b152cdbc
isPrivate:false
message:"My name is max"
gender:"unisex"
age: "20"
createdBy:abcff9ef71fa048cea3c8a97
}

Now I want those messages that was created by the abc... first. All those records that match a certain id would come first and then rest of the records would remain the same

{
_id:abc0aa8573bfa917b152cdbc
isPrivate:false
message:"My name is stark"
gender:"unisex"
age: "19"
createdBy:abcff9ef71fa048cea3c8a97
}

{
    _id:abc0aa8573bfa917b152cdbc
    isPrivate:false
    message:"My name is max"
    gender:"unisex"
    age: "20"
    createdBy:abcff9ef71fa048cea3c8a97
    }
    {
    _id:abc0aa8573bfa917b152cdbc
    isPrivate:false
    message:"My name is james"
    gender:"unisex"
    age: "20"
    createdBy:defff9ef71fa048cea3c8a97
    }
    {
    _id:abc0aa8573bfa917b152cdbc
    isPrivate:false
    message:"My name is harry"
    gender:"unisex"
    age: "20"
    createdBy:defff9ef71fa048cea3c8a97
    }
    

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I don't think there is any straight way to do this, If you really want to then try $cond operator to check condition on specific field,

  • add new field matchResult in $project it will check createdBy is matching return 1 otherwise 0,
  • $sort by matchResult in descending order
const [messages, messageCount] = await Promise.all([
    MessageModel.aggregate([
        { $match: params },
        {
            $project: {
                ...filterObject,
                matchResult: {
                    $cond: [
                      { $eq: ["$createdBy", ObjectId("abcff9ef71fa048cea3c8a97")] },
                      1,
                      0
                    ]
                }
            }
        },
        { $sort: { matchResult: -1 } },
        { $skip: ctx.paginate.skip },
        { $limit: ctx.query.limit }
    ]),
    MessageModel.countDocuments(params),
]);

Playground


Second option is $regexMatch aggregation operator starting from MongoDB v4.2,

Playground

I am not recommending this approach for big data in collection, this may cause performance issue, it is better to sort in your client side after query.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...