Twois
Twois

Reputation: 598

Mongodb sort by in array

Is there a way to sort by a given array?

something like this:

const somes = await SomeModel.find({}).sort({'_id': {'$in': [ObjectId('sdasdsd), ObjectId('sdasdsd), ObjectId('sdasdsd)]}}).exec()

What i looking for is a way to get a solution, to get all document of the collection and sort by if the document's _id match with one of the given array.

An example:

we have albums collection and songs collection. In albums collection we store the ids of the songs that belongs to the albums.

I want to get the songs, but if the song is in the album take them front of the array.

I solved this as follow, but its looks a bit hacky:

const songs = await SongMode.find({}).skipe(limit * page).limit(limit).exec();
const album = await AlbumModel.findById(id).exec();

if(album) {
    songArr = album.songs.slice(limit * page);

    for(let song of album.songs) {
        songs.unshift(song);
        songs.pop();
    }
}

Upvotes: 0

Views: 134

Answers (1)

B. Fleming
B. Fleming

Reputation: 7220

This cannot be accomplished using an ordinary .find().sort(). Instead, you will need to use the MongoDB aggregation pipeline (.aggregate()). Specifically, you will need to do the following:

  1. Perform a $projection such that if the _id is $in the array, your new sort_field is given the value 1, otherwise it's given a value of 0.
  2. Perform a $sort such that you're doing a descending sort on the new sort_field.

If you're using MongoDB version 3.4 or greater, then this is easy because of the $addFields operator:

const your_array_of_ids = [
    ObjectId('objectid1'),
    ObjectId('objectid2'),
    ObjectId('objectid3')
];

SomeModel.aggregate([
    { '$addFields': {
        'sort_field': { '$cond': {
            'if': { '$in': [ '$_id', your_array_of_ids ] },
            'then': 1,
            'else': 0
        }}
    }},
    { '$sort': {
        'sort_field': -1
    }}
]);

If you're using an older version of MongoDB, then the solution is similar, but instead of $addFields you will be using $project. Additionally, you will need to explicitly include all of the other fields you want included, otherwise they will be excluded from the results.

Upvotes: 1

Related Questions