Robin Heggelund Hansen
Robin Heggelund Hansen

Reputation: 5006

Mongoose: Only return one embedded document from array of embedded documents

I've got a model which contains an array of embedded documents. This embedded documents keeps track of points the user has earned in a given activity. Since a user can be a part of several activities or just one, it makes sense to keep these activities in an array. Now, i want to extract the hall of fame, the top ten users for a given activity. Currently i'm doing it like this:

userModel.find({ "stats.activity": "soccer" }, ["stats", "email"])
.desc("stats.points")
.limit(10)
.run (err, users) ->

(if you are wondering about the syntax, it's coffeescript)

where "stats" is the array of embedded documents/activeties.

Now this actually works, but currently I'm only testing with accounts who only has one activity. I assume that something will go wrong (sorting-wise) once a user has more activities. Is there anyway i can tell mongoose to only return the embedded document where "activity" == "soccer" alongside the top-level document?

Btw, i realize i can do this another way, by having stats in it's own collection and having a db-ref to the relevant user, but i'm wondering if it's possible to do it like this before i consider any rewrites.

Thanks!

Upvotes: 0

Views: 1459

Answers (1)

Asya Kamsky
Asya Kamsky

Reputation: 42342

You are correct that this won't work once you have multiple activities in your array.

Specifically, since you can't return just an arbitrary subset of an array with the element, you'll get back all of it and the sort will apply across all points, not just the ones "paired" with "activity":"soccer".

There is a pretty simple tweak that you could make to your schema to get around this though. Don't store the activity name as a value, use it as the key.

{ _id: userId,
  email: email,
  stats: [
    {soccer : points},
    {rugby:   points},
    {dance:   points}
  ]
}

Now you will be able to query and sort like so:

users.find({"stats.soccer":{$gt:0}}).sort({"stats.soccer":-1})

Note that when you move to version 2.2 (currently only available as unstable development version 2.1) you would be able to use aggregation framework to get the exact results you want (only a particular subset of an array or subdocument that matches your query) without changing your schema.

Upvotes: 1

Related Questions