3

I was looking for a way to sort array of object by an arbitrary list. Lets assume I have this array of objects.

[
  {
   "_id": "4JEEuhNIae",
   "category": "grocery"
  },
  {
   "_id": "4JW7miNITl",
   "category": "food"
  },
  {
   "_id": "4Je4kmrrbZ",
   "category": "coffee"
  },
  {
   "_id": "4JgAh3N86x",
   "category": "coffee"
  }
]

This is the array that I would like to use as sorting criteria. Records with foodshould come first, then coffeeand grocery.

['food','coffee','grocery']

Result should be:

[
  {
   "_id": "4JW7miNITl",
   "category": "food"
  },
  {
   "_id": "4Je4kmrrbZ",
   "category": "coffee"
  },
  {
   "_id": "4JgAh3N86x",
   "category": "coffee"
  },
  {
   "_id": "4JEEuhNIae",
   "category": "grocery"
  },
]

How can I do this type of sorting on mongodb by using mongoose? I really don't want to make any operations on the code after fetching data.

2
  • 1
    Your code is a list field inside a document ? Or it is a list of documents ? Commented Nov 1, 2016 at 9:01
  • @SergiuZaharie it is a list of documents Commented Nov 1, 2016 at 10:14

1 Answer 1

2

You could try running a custom comparator function with the native JavaScript sort() method on the array returned from the cursor.toArray() method:

var order = ["food", "coffee", "grocery"];
var docs = db.collection.find().toArray().sort(function(a, b) { 
    return order.indexOf(a.category) - order.indexOf(b.category);
});
printjson(docs);

Sample Output

[
    {
        "_id" : "4JW7miNITl",
        "category" : "food"
    },
    {
        "_id" : "4Je4kmrrbZ",
        "category" : "coffee"
    },
    {
        "_id" : "4JgAh3N86x",
        "category" : "coffee"
    },
    {
        "_id" : "4JEEuhNIae",
        "category" : "grocery"
    }
]

With the new MongoDB 3.4 version, you should be able to leverage the use of the native MongoDB operators $addFields and $indexOfArray in the aggregation framework.

  • The $addFields pipeline step allows you to $project new fields to existing documents without knowing all the other existing fields.
  • The $indexOfArray expression returns position of particular element in a given array.

So putting that altogether you could try the following aggregate operation (with MongoDB 3.4):

var order = ["food", "coffee", "grocery"],
    projection = { 
        "$addFields" : { 
            "__order" : { "$indexOfArray" : [ order, "$category" ] } 
        } 
    },
    sort = { "$sort" : { "__order" : 1 } };
db.collection.aggregate([ projection, sort]);
Sign up to request clarification or add additional context in comments.

1 Comment

It seems i can't directly write custom sort function for mongoose, github.com/Automattic/mongoose/issues/798 I need to use db.eval well thank you

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.