Mongoose切片数组,在填充的字段中

时间:2016-05-18 17:35:17

标签: node.js mongodb mongoose

我有以下mongoose架构:

主要是userSchema,其中包含一系列朋友, friendSchema。每个friendSchema都是一个包含messageSchema数组的对象。 messageSchema是最深的对象,包含消息的正文。

var messageSchema = new mongoose.Schema({
    ...
    body: String
});

var conversationsSchema = new mongoose.Schema({
    ...
    messages: [messageSchema]
});

var friendSchema = new mongoose.Schema({
  user: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
  },
  conversation: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Conversation',
  },
}, { _id : false });


var userSchema = new mongoose.Schema({
    ...
    friends: [friendSchema]
});

在检索特定用户的朋友时,我会填充其朋友个人资料,如果存在对话,我也会填充对话。 如何切片conversations.messages数组,它位于conversation对象的总体中?我不想回复整个消息。

  var userId = req.userid;
  var populateQuery = [{ path:'friends.user', 
                         select: queries.overviewConversationFields },
                       { path:'friends.conversation' }];

  User
  .find({ _id: userId }, { friends: 1 })
  .populate(populateQuery)
  .exec(function(err, result){
    if (err) { next(err); }
    console.log(result);
  }

编辑(1):我试过了

  .slice('friends.conversation.messages', -3)

编辑(2):我尝试了填充查询

  { path:'friends.conversation', options: { 'friends.conversation.messages': { $slice: -2 } }

编辑(3):现在,我可以实现我想要的,在执行查询后切片。这根本没有优化。

1 个答案:

答案 0 :(得分:1)

一个有效的解决方法。 我没有找到如何$slice一个位于填充字段中的数组。

$slice运算符在任何array上都可以正常工作,只要其父文档没有填充。

1)我决定通过添加一个包含对话中涉及的用户ID的数组来更新conversationSchema

var conversationsSchema = new mongoose.Schema({
    users: [type: mongoose.Schema.Types.ObjectId],
    messages: [messageSchema]
});

2)然后,我可以轻松找到用户参与的每个对话。 正如我所说的,我可以正确地对messages数组进行切片,因为不需要填充任何内容。

Conversation.find({ users: userId }, 
                  { 'messages': { $slice: -1 }}, function(err, conversation) {
});

3)最后我要做的就是分别查询所有朋友和对话,然后将所有内容放回原点,并使用简单的循环和_find。 那将或多或少与Mongo population

相同的程序

使用async.parallel提高效率:

 async.parallel({
      friends: function(done){
        User
          .find({ _id: userId }, { friends: 1 })
          .populate(populateQuery)
          .exec(function(err, result){
          if (err) { return done(err);}
          done(null, result[0].friends);
        });
      },
      conversations: function(done){
        Conversation.find({ users: userId }, { 'messages': { $slice: -1 }}, function(err, conversation) {
          if (err) { return done(err); }
          done(null, conversation)
        });
      }}, function(err, results) {
          if (err) { return next(err); }

          var friends = results.friends;
          var conversations = results.conversations;

          for (var i = 0; i < friends.length; i++) {
            if (friends[i].conversation) {
              friends[i].conversation = _.find(conversations, function(conv){ 
                return conv._id.equals(new ObjectId(friends[i].conversation));
              });
            }
          }

      });
      // Friends contains now every conversation, with the last sent message.