Architucas
Architucas

Reputation: 129

mongo sort by group criteria

I have data structure like this (mongo 2.6):

{"player":"John Doe","active":true}

lets say I use the term "ohn" when performing search, I need to sort based on certain criteria:

  1. players whose name is "ohn" AND active
  2. players whose name CONTAINS "ohn" AND active
  3. players whose name is "ohn" but NOT active
  4. players whose name CONTAINS "ohn" but NOT active

how do I achieve this in mongo 2.6? the expected output is all players who meets any of those 4 criteria, but sorted in that order (players who meet crit 1, then players who meet crit 2, and so on). I also want to add pagination (skip and limit) thanks

Upvotes: 0

Views: 455

Answers (3)

Rubin Porwal
Rubin Porwal

Reputation: 3845

db.collection.aggregate(

    // Pipeline
    [
        // Stage 1
        {
            $match: {
                $or: [{
                    $text: {
                        $search: "ohn"
                    }
                }, {
                    player: /ohn/i
                }],
                active: {
                    $in: [true, false]
                }
            }
        },

        // Stage 2
        {
            $sort: {
                active: -1
            }
        },

    ]



); 

In above mentioned aggregate query text search is performed to filter and sort documents from MongoDB collection according to criteria mentioned into description of question.

Text Index needs to be applied to fields which needs to be filtered to perform text based search into MongoDB collection.

Upvotes: 0

Here I create addition columns call point for sorting

  1. active = true give 2 point
  2. whole player contain word give 1 point

And sort result by point descending. Here is query

    db.yourtable.aggregate(
        [ 
             { $match : { "player": /ohn/i } } /* select all contain ohn ignore case */
            ,{ $project:{
                player: 1,
                active: 1,
                point: { $add: [ 
                                {$cond: { if: { $eq: [ "$active", true ] }, then: 2, else: 0 }}                      /* active = true give 2 point */
                                , {$cond: { if: { $eq: [ { $toLower: "$player" }, 'ohn' ] }, then: 1, else: 0 }}     /* player contain whole word give 1 point */
                        ]}

                }
            }
            ,{ $sort : { point : -1 } }  /* sort by point */
        ]
    );

I ignore case sensitive, hope this help

Upvotes: 1

Rahul Sharma
Rahul Sharma

Reputation: 10071

Try this, Hope this will help.

db.getCollection('TEST').find({}).sort({"active":-1}).toArray().reduce(function(doc1, doc2) {
    if(doc2.player == "ohn" && doc2.active)
        doc1.unshift(doc2)
    else
        doc1.push(doc2)
  return doc1; 
},[]);

Upvotes: 0

Related Questions