mongoose子文档排序

tsm*_*tsm 6 mongoose mongodb node.js

我有一个文章架构,其中有一个子文档comments,其中包含我为此特定文章所获得的所有注释.

我想要做的是按ID选择一篇文章,填写其作者字段以及评论中的作者字段.然后按日期对注释子文档进行排序.

文章架构:

var articleSchema = new Schema({
  title: { type: String, default: '', trim: true },
  body: { type: String, default: '', trim: true },
  author: { type: Schema.ObjectId, ref: 'User' },
  comments: [{
    body: { type: String, default: '' },
    author: { type: Schema.ObjectId, ref: 'User' },
    created_at: { type : Date, default : Date.now, get: getCreatedAtDate }
  }],
  tags: { type: [], get: getTags, set: setTags },
  image: {
    cdnUri: String,
    files: []
  },
  created_at: { type : Date, default : Date.now, get: getCreatedAtDate }
});
Run Code Online (Sandbox Code Playgroud)

文章架构上的静态方法:(我想在这里对评论进行排序,我可以这样做吗?)

  load: function (id, cb) {
    this.findOne({ _id: id })
      .populate('author', 'email profile')
      .populate('comments.author')
      .exec(cb);
  },
Run Code Online (Sandbox Code Playgroud)

我必须在其他地方进行排序:

exports.load = function (req, res, next, id) {
  var User = require('../models/User');

  Article.load(id, function (err, article) {
    var sorted = article.toObject({ getters: true });
    sorted.comments = _.sortBy(sorted.comments, 'created_at').reverse();

    req.article = sorted;
    next();
  });
};
Run Code Online (Sandbox Code Playgroud)

我打电话toObject将文档转换为javascript对象,我可以保留我的getters/virtuals,但是方法呢?

无论如何,我在普通对象上做了排序逻辑并完成了.

我很确定有更好的方法,请告诉我.

Bla*_*ven 9

我可以把它写成一些东西,但考虑到"让猫鼬物体回来"似乎是主要的考虑因素.

所以你可以"做"各种各样的事情.但是,既然你正在"填充引用"到一个对象中然后想要改变数组中对象的顺序,那么实际上只有一种方法可以解决这个问题.

在创建数据时按顺序修复数据


如果你希望你的"comments"数组按照它们"created_at"的日期排序,这甚至分解为多种可能性:

  1. 它"应该"已经添加到"插入"顺序中,所以"最新"是你记下的最后一个,但你也可以在最近(过去几年)版本的MongoDB中$position修改它作为修饰符$push:

    Article.update(
        { "_id": articleId },
        { 
            "$push": { "comments": { "$each": [newComment], "$position": 0 } }
        },
        function(err,result) {
            // other work in here
        }
    );
    
    Run Code Online (Sandbox Code Playgroud)

    这将"数组"元素"前置"到"first"(0)索引处的现有数组,因此它始终位于前面.

  2. 由于逻辑原因或者您"想要确定"的地方未能使用"位置"更新,因此$sort修改器可以使用甚至更长的时间$push:

    Article.update(
        { "_id": articleId },
        { 
            "$push": { 
                "comments": { 
                    "$each": [newComment], 
                    "$sort": { "$created_at": -1 } 
                }
            }
        },
        function(err,result) {
            // other work in here
        }
    );
    
    Run Code Online (Sandbox Code Playgroud)

    这将对包含每次修改的指定值的数组元素文档的属性进行"排序".你甚至可以这样做:

    Article.update(
        {  },
        { 
            "$push": { 
                "comments": { 
                    "$each": [], 
                    "$sort": { "$created_at": -1 } 
                }
            }
        },
        { "multi": true },
        function(err,result) {
            // other work in here
        }
    );
    
    Run Code Online (Sandbox Code Playgroud)

    这将在一次点击中按指定字段对整个集合中的每个"注释"数组进行排序.

.aggregate()在完成该操作之后或在.sort()普通对象上执行自己的操作之后,可以使用其他解决方案来对数组进行排序和/或"重新转换"为mongoose 对象.

这两者都涉及创建单独的模型对象和包含"引用"信息的嵌入项的"模式".因此,您可以处理这些问题,但是当您可以将数据排序为"最需要的"时,这似乎是不必要的开销.

另一种方法是确保像"虚拟"这样的字段始终"序列化"为.toObject()随叫随到的对象格式,并且只是现在所有方法都已消失,并使用所呈现的属性.

最后一种是"理智"的方法,但如果你通常使用的是"created_at"顺序,那么以每次操作的方式"存储"你的数据更有意义所以当你"检索"它时,它会保留在命令您将要使用.