6
votes

well i have the following shemas:


    var BrandSchema = new Schema({
      name: {
        type: String,
        required: true,
        index: {
          unique: true
        },
        lowercase: true
      },
      logo: {
        type: ObjectId,
        ref: 'Image'
      }
    });

    var FollowActionSchema = new Schema({
      'actionDate': {
        type: Date,
        'default': Date.now
      },
      'brand': {
        type: ObjectId,
        ref: 'Brand'
      },
      'performer': {
        type: ObjectId,
        ref: 'User'
      },
      'type': String // followUser, folloBrand, followMerchant
    });

What i want is getting the user following brands, sorting by brand name, so for do that i did the query to FollowAction and find all the FollowActions that user did and then i populate the brand field.

So the problem is that i can't sort the query for the brand name, the only way i know to do that is by returning all documents and sort them from nodejs app. Anyone knows how can i do that?? or if i should change the shema structure??

The query that i do is:


       async.waterfall([
        function findActions(next) {
          var options = {
            query: {
              performer: userId,
              $or: [{
                type: 'followBrand'
              }, {
                type: 'followMerchant'
              }]

            },
            projection: {
              actionDate: 1,
              brand: 1,
              merchant: 1,
              type: 1
            },
            sort: '-actionDate',
            pagination: pagination
          };
          utils.limitQuery('FollowAction', options, next);
        },
        function inflate(actions, next) {
          total = actions.count;
          var options = {
            projection: {
              name: 1,
              _id: 1,
              username: 1
            }
          };
          async.eachSeries(actions.result, function(action, done) {
            async.waterfall([
              function inflateAction(done) {
                action.inflate(options, done);
              },
              function addToArray(item, done) {
                trusted.push({
                  _id: item._id,
                  name: utils.capitalize(item.name || item.username),
                  type: item.name ? 'brand' : 'merchant'
                });
                return done(null, item);
              }
            ], done);
          }, next);
        }
      ], function(err) {
        callback(err, trusted, total);
      });

2
Have you tried sorting before populating?B3rn475
Please can you post your actual code where you do queries? So we can integrate with ours.michelem
i edited the original post with the query. it's possible to sorting with populated field before populate this field?Javier Blanco Martinez

2 Answers

2
votes

The Mongoose API does seem to support sorting on populated fields, but there's a bug that breaks it entirely: https://github.com/Automattic/mongoose/issues/2202. You get a result, but it's just plain wrong.

For small amounts of data, it's fine to sort the result array using Javascript Array.prototype.sort(). Keep in mind that this directly modifies the sorted array though.

What I've done in this case is add a sort key property to the schema for the model you want to sort. For your example, you could do:

var FollowActionSchema = new Schema({
  // ...
  'brandSortKey': { type: String },
  'brand': {
    type: ObjectId,
    ref: 'Brand'
  },
  // ...
});

This isn't perfect, because you'll have to explicitly set this property with the correct key yourself:

var FollowAction = Model('FollowAction', FollowActionSchema);

var aBrand = // some brand object

var f = new FollowAction({
   brand: aBrand._id,
   brandSortKey: aBrand.name
   // other properties
}); 

But, then you can sort directly via the Mongoose API (or MongoDB):

FollowAction.find({})
   .sort({ brandSortKey:1 })
   .exec(function (err, sortedResults) {
       // do something with sorted results.
   });
0
votes

Get the idea from this simple example

 Post.find({'_id': userId})
           .limit(10)
           .skip(0)
           .sort({'created_at':-1}) // this is used to sort
           .exec(function(error, result){
            if(!error){
              // console.log(result);
              res.send({data:result});
            } else{
              console.log(error);
            }
        });