Amir Rahbaran
Amir Rahbaran

Reputation: 2430

Meteor: How to sort documents by the first item of an array

Research papers should be sorted by the author's last name. This is how a JSON looks like with one author:

{
    "_id" : "ADnijjRpoWkTEGgkc",
    "authors" : [ 
        {
            "lastName" : "Rahbaran",
            "firstName" : "Amir"
        }
    ],
    "title" : "Bricolage revisted",
    "outlet" : "Journal of Strategic Management",
    "year" : "2017",
    "abstract" : "dicta sunt explicabo. Nemo enim ..."
}

The corresponding Template helper works perfectly if there's only one author stored:

return Publications.find({}, {
      sort: {"authors.lastName": -1}
    }).fetch(); 

The problem: In many cases, you have multiple authors for a single research paper:

This would be the JSON:

{
    "_id" : ObjectId("56b06047204a563ca4207e8e"),
    "authors" : [ 
        {
            "lastName" : "Lennon",
            "firstName" : "John"
        }, 
        {
            "lastName" : "McCartney",
            "firstName" : "Paul"
        }
    ],
    "title" : "The Beatles - revisted",
    "outlet" : "Journal of Great Music",
    "year" : "1968",
    "abstract" : "Ob-La-Di, Ob-La-Da ... "
}

Now, I tried sort: {"authors.lastName.0": -1} or sort: {"authors.lastName[0]": -1} to no avail.

I came along concepts of map, reduce and aggregate but wouldn't know how to apply here and if it's necessary, respectively.

Or maybe Meteor has package or "trick" for that?

Any help really appreciated.

Upvotes: 2

Views: 195

Answers (3)

chridam
chridam

Reputation: 103365

Another alternative using the aggregation framework through the aggregate() method, you can sort the authors array as well as the documents. Though aggregate() isn't supported yet in meteor, you need to get the aggregation framework package installed - it doesn't do anything to fancy, just wraps up some Mongo methods for you.

Just meteor add meteorhacks:aggregate and you should be in business. This will add proper aggregation support for Meteor.

Now you would need to run this pipeline to achieve the desired result:

var pipeline = [
    { "$unwind": "authors" },
    { "$sort": { "authors.lastName": -1 } },
    {
        "$group": {
            "_id": "$authors",
            "authors": { "$push": "$authors" },
            "title": { "$first": "$title" },
            "outlet": { "$first": "$outlet" },
            "year": { "$first": "$year" },
            "abstract": { "$first": "$abstract" }
        }
    },
    { "$sort": { "authors.lastName": -1 } },
];

return Publications.aggregate(pipeline);

Upvotes: 1

Alex Blex
Alex Blex

Reputation: 37048

db.publications.find({}).sort({"authors.lastName":-1})

Works perfectly fine. It sorts authors array within document first, picks the first element, and then sorts documents. Documentation.

Upvotes: 1

corvid
corvid

Reputation: 11187

Assuming that you always have at least one author, you can do the following:

Publications.find({}, {
  sort: {
    'authors.0.lastName': -1
  }
});

Upvotes: 1

Related Questions