7

Consider the following is my document stored in collection Users

{
  _id : "User1",
  joined : ISODate("2011-03-02"),
  likes : {
           sublikes: [
                      {WebsiteID:'001': WebsiteName: 'ABCD'},
                      {WebsiteID:'002': WebsiteName: '2BC2'},
                      {WebsiteID:'003': WebsiteName: '3BC3'},
                      //........... 
                      //........... 
                      {WebsiteID:'999999': WebsiteName: 'SOME_NAME'}
                     ]
          }
}

Now using mongodb aggregation framework I need to fetch that

collection.aggregate([
                        { $project: {
                            _id: 1,
                            "UserID": "$_id", 
                            "WebsiteName": "$likes.sublikes[0]['WebsiteName']"
                        }
                        },
                         { $match: { _id: 'User1'} }
                      ], function (err, doc) {
 ///Not able to get the WebsiteName: 'ABCD'
});

If I use $unwind the document becomes bulk (specifically in the above case), So I don't want to unwind it for getting only first item in an array (irrespective of others)

Can anyone give me hints on how to access is and rename that field?


Update 1: Even I tried to project with "WebsiteName": "$likes.sublikes.0.WebsiteName". Didn't work :-(

Update 2: Open issue - https://jira.mongodb.org/browse/SERVER-4589

As of now $at does not work. Throws an error:

{ [MongoError: exception: invalid operator '$at']
  name: 'MongoError',
  errmsg: 'exception: invalid operator \'$at\'',
  code: 15999,
  ok: 0 }

Till then using $unwind

// Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
  var rest = this.slice((to || from) + 1 || this.length);
  this.length = from < 0 ? this.length + from : from;
  return this.push.apply(this, rest);
};
4
  • Wouldn't you instead use normal querying with the $slice ( docs.mongodb.org/manual/reference/projection/slice ) operator like so: db.col.find({_id: 'User1'}, {'likes.sublikes': {$slice: 1}}) ? Commented Apr 10, 2013 at 13:14
  • 1
    The open issue in Jira that you've referenced (SERVER-4589) is a feature request so the $at operator does not exist yet. You can vote/watch the feature in Jira to track progress. Commented Apr 11, 2013 at 6:54
  • 1
    FYI, you should also have your $match at the beginning of the aggregation pipeline if you want it to take advantage of an index. See the Optimizing Performance details in the MongoDB documentation. Commented Apr 11, 2013 at 7:11
  • @Stennie you are absolutely right. Thanks for reminding... Commented Apr 11, 2013 at 9:43

1 Answer 1

10

The easiest way to achieve your result is using a normal find query and the $slice operator:

db.collection.find( {_id: "User1"}, {"likes.sublikes": {$slice: 1}} )

The aggregation framework (as at MongoDB 2.4.1) does not support $slice or array indexes (vote/watch feature requests: SERVER-6074 and SERVER-4589).

You could do this in aggregation framework using $unwind, $group and the $first operator, eg:

db.collection.aggregate([
    { $match: {
         _id : "User1"
    }},
    { $unwind: "$likes.sublikes" },
    { $group: {
        _id: "$_id",
        like: { $first: "$likes.sublikes" }
    }},
    { $project: {
        _id: 0,
        "UserID": "$_id",
        "WebsiteName": "$like.WebsiteName"
    }}
])

The normal $slice should be the most performant option.

Sign up to request clarification or add additional context in comments.

Comments

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.