填充中的Mongoose排序不起作用

时间:2016-04-16 23:43:11

标签: javascript node.js mongodb mongoose mongodb-query

我试图通过降序日期顺序对我的通知进行排序。我相信他们目前正在升序。我尝试了两种不同的方法来在我的填充语句中对通知进行排序

尝试1

Notification.populate(user.notifications, { path: 'project', model: 'Project', sort: { 'created': -1 }},
                        function(err, notifications) {
                            // console.log('nested population of user', notifications);
                            socket.emit('take notifications', {
                                notifications: notifications,
                                num_unread: unread
                            });
                        });

尝试2

Notification.populate(user.notifications, { path: 'project', model: 'Project', sort: { 'created': -1 }},
                        function(err, notifications) {
                            // console.log('nested population of user', notifications);
                            socket.emit('take notifications', {
                                notifications: notifications,
                                num_unread: unread
                            });
                        });

我也试过切换1和-1参数,但这没有做任何事情。

通知架构

var NotificationSchema = new Schema({
    created: {
        type: Date,
        default: Date.now
    },
    type: {
        type: String,
        enum: ['rfc']
    },
    read: {
        type: Boolean,
        default: false
    },
    from: {
        type: Schema.ObjectId,
        ref: 'User'
    },
    project: {
        type: Schema.ObjectId,
        ref: 'Project'
    }
});

1 个答案:

答案 0 :(得分:1)

这不是.populate()形式与"sort"选项一起使用的方式,因为该选项具有不同的预期用法。

您基本上只需要常规JavaScript Array.sort(),或者因为您要排序的属性在填充之前已经在父文档中,那么只需将.sort()光标修饰符应用于初始$lookup 1}}无论如何。

所以在.find()查询中:

.find()

或使用Notification.find() .populate({ path: 'project', model: 'Project'}) .sort({ "created": -1 }) .exec(function(err,notifications) { // sorted by cursor }); 调用Model.populate()数组内容:

Array.sort()

因此,根据您的情况,当前字段上的父项的Notification.populate( user.notifications, { path: 'project', model: 'Project' }, function(err,notifications) { notifications.sort(function(a,b) { return a.created < b.created }); // now it's sorted } ) 而不是已填充的项目要么通过“游标”排序应用,要么只是对手中的常规数组进行排序。

预期用途说明

考虑以下示例,其中这将是“用户”模型内容:

.sort()

然后有关于“追随者”项目的集合:

{
  "_id" : ObjectId("5712ebbc37ba497f25b6b800"),
  "name" : "Bill",
  "sport" : ObjectId("5712e5af18a74c2810d5a5a8"),
  "followers" : [
          ObjectId("5712e001a83d6da651770e27"),
          ObjectId("5712e05da83d6da651770e28"),
          ObjectId("5712e06fa83d6da651770e29")
  ]
}
{
  "_id" : ObjectId("5712ebbc37ba497f25b6b801"),
  "name" : "Ted",
  "sport" : ObjectId("5712e5da18a74c2810d5a5a9"),
  "followers" : [
          ObjectId("5712e001a83d6da651770e27"),
          ObjectId("5712e06fa83d6da651770e29")
  ]
}

当然还有“运动”项目:

{ "_id": ObjectId("5712e001a83d6da651770e27"), "name": "Fred" },
{ "_id": ObjectId("5712e05da83d6da651770e28"), "name": "Sally" },
{ "_id": ObjectId("5712e06fa83d6da651770e29"), "name": "Abe" }

{ "_id" : ObjectId("5712e5af18a74c2810d5a5a8"), "name" : "Tennis" } { "_id" : ObjectId("5712e5da18a74c2810d5a5a9"), "name" : "Golf" } 的“排序”选项可用于处理“关注者”内容之类的内容,当填充此内容时,项目将反映“排序”的顺序,而不是它们发生的顺序。人口之前的数组内的序列。

因此,即使您为两个填充路径提供了“排序”选项,也只会对“数组”内容进行实际排序:

.populate()

结果将是:

  User.populate(
    users,
    [
      { "path": "sport", "options": { "sort": { "name": 1 } } },
      { "path": "followers", "options": { "sort": { "name": 1 } } }
    ],
    function(err,users) {
      console.log(JSON.stringify(users,undefined,2));
      callback(err);
    }
  );

这是正常行为,正如预期的那样。但是你要问的是“排序”由人口填充的属性返回的[ { "_id": "5712ebbc37ba497f25b6b800", "name": "Bill", "sport": { "_id": "5712e5af18a74c2810d5a5a8", "name": "Tennis", "__v": 0 }, "__v": 0, "followers": [ { "_id": "5712e06fa83d6da651770e29", "name": "Abe", "__v": 0 }, { "_id": "5712e001a83d6da651770e27", "name": "Fred", "__v": 0 }, { "_id": "5712e05da83d6da651770e28", "name": "Sally", "__v": 0 } ] }, { "_id": "5712ebbc37ba497f25b6b801", "name": "Ted", "sport": { "_id": "5712e5da18a74c2810d5a5a9", "name": "Golf", "__v": 0 }, "__v": 0, "followers": [ { "_id": "5712e06fa83d6da651770e29", "name": "Abe", "__v": 0 }, { "_id": "5712e001a83d6da651770e27", "name": "Fred", "__v": 0 } ] } ] 列表。这是完全不同的事情,由数组上的常规客户端users处理:

.sort()

实际上,实际上对列表进行排序就像排序任何常规数组一样。这是对填充属性进行排序的方式,因为人口实际上发生在客户端中。

查找和排序的服务器端处理

在某些情况下,您确实希望在服务器上进行此类操作。这样的事情包括“分页”结果,将所有结果返回给客户端API然后在排序后只提取所需页面效率不高。

现在版本的MongoDB从v3.2.x开始向上包括$lookup聚合管道方法。这基本上做 User.populate( users, [ { "path": "sport", "options": { "sort": { "name": 1 } } }, { "path": "followers", "options": { "sort": { "name": 1 } } } ], function(err,users) { users.sort(function(a,b) { return a.sport.name > b.sport.name; }); console.log(JSON.stringify(users,undefined,2)); callback(err); } ); 在“客户端”上所做的事情,而不是“服务器”。

它没有所有相同的选项来过滤或直接从$lookup“排序”项目,但由于这是在聚合框架中实现的,因此这些操作可以在不同的管道阶段执行。

包含一个示例列表,其中显示了使用.populate()在客户端中处理.sort()以及使用$lookup的聚合管道技术。

两者都得出相同的结果,区别在于{{3}}是在返回客户端API之前需要对结果进行排序的技术,例如“分页”数据时。 / p>

.populate()

输出

var async = require('async'),
    mongoose = require('mongoose'),
    Schema = mongoose.Schema;

mongoose.connect('mongodb://localhost/follower');

var sportSchema = new Schema({
  name: String
});

var followerSchema = new Schema({
  name: String
});

var userSchema = new Schema({
  name: String,
  sport: { type: Schema.Types.ObjectId, ref: 'Sport' },
  followers: [{ type: Schema.Types.ObjectId, ref: 'Follower' }]
});

var Sport = mongoose.model('Sport',sportSchema),
    Follower = mongoose.model('Follower',followerSchema),
    User = mongoose.model('User',userSchema);

async.series(
  [
    function(callback) {
      async.each([Sport,Follower,User],function(model,callback) {
        model.remove({},callback);
      },callback);
    },
    function(callback) {
      async.parallel(
        [
          function(callback) {
            Sport.create([
              { "_id": "5712e5af18a74c2810d5a5a8", "name": "Tennis" },
              { "_id": "5712e5da18a74c2810d5a5a9", "name": "Golf" }
            ],callback);
          },
          function(callback) {
            Follower.create([
              { "_id": "5712e001a83d6da651770e27", "name": "Fred" },
              { "_id": "5712e05da83d6da651770e28", "name": "Sally" },
              { "_id": "5712e06fa83d6da651770e29", "name": "Abe" }
            ],callback);
          },
          function(callback) {
            User.create([
              {
                 "name": "Bill",
                 "sport": "5712e5af18a74c2810d5a5a8",
                 "followers": [
                    "5712e001a83d6da651770e27",
                    "5712e05da83d6da651770e28",
                    "5712e06fa83d6da651770e29"
                  ]
              },
              {
                 "name": "Ted",
                 "sport": "5712e5da18a74c2810d5a5a9",
                 "followers": [
                    "5712e001a83d6da651770e27",
                    "5712e06fa83d6da651770e29"
                  ]
              }
            ],callback);
          }
        ],
        callback
      );
    },
    function(callback) {
      console.log("Populate Output");
      User.find().exec(function(err,users) {
        if (err) callback(err);
        User.populate(
          users,
          [
            { "path": "sport", "options": { "sort": { "name": 1 } } },
            { "path": "followers", "options": { "sort": { "name": 1 } } }
          ],
          function(err,users) {
            users.sort(function(a,b) {
              return a.sport.name > b.sport.name;
            });
            console.log(JSON.stringify(users,undefined,2));
            callback(err);
          }
        );
      });
    },
    function(callback) {
      console.log("Aggregate Output");
      User.aggregate(
        [
          { "$lookup": {
            "from": "sports",
            "localField": "sport",
            "foreignField": "_id",
            "as": "sport"
          }},
          { "$unwind": "$sport" },
          { "$unwind": "$followers" },
          { "$lookup": {
            "from": "followers",
            "localField": "followers",
            "foreignField": "_id",
            "as": "followers"
          }},
          { "$unwind": "$followers" },
          { "$sort": { "_id": 1, "followers.name": 1 } },
          { "$group": {
            "_id": "$_id",
            "name": { "$first": "$name" },
            "sport": { "$first": "$sport" },
            "followers": { "$push": "$followers" }
          }},
          { "$sort": { "sport.name": 1 } }
        ],
        function(err,users) {
          console.log(JSON.stringify(users,undefined,2));
          callback(err);
        }
      );
    }
  ],
  function(err) {
    if (err) throw err;
    mongoose.disconnect();
  }
);