【问题标题】:Populate Query Options with Async Waterfall使用异步瀑布填充查询选项
【发布时间】:2018-03-31 00:58:23
【问题描述】:

我正在尝试 mongoose populate 查询选项,但我不知道为什么查询选项不起作用。

我有用户架构:

const mongoose = require('mongoose');
const Schema   = mongoose.Schema;

const UserSchema = new Schema(
  {
    username: { type: String, required: true },
    email: { type: String },
    name: { type: String },
    address: { type: String }
  },
  { timestamps: true }
);
module.exports = mongoose.model('User', UserSchema);

和提要架构:

const mongoose = require('mongoose');
const Schema   = mongoose.Schema;

const FeedSchema = new Schema(
  {
    user: { type: Schema.ObjectId, ref: 'User' },
    notes: { type: String, required: true },
    trx_date: { type: Date },
    status: { type: Boolean, Default: true }
  },
  { timestamps: true }
);

FeedSchema.set('toObject', { getters: true  });

module.exports = mongoose.model('Feed', FeedSchema);

我想通过user id 找到所有feed,我使用了async waterfall,如下代码:

async.waterfall([
  function(callback) {
    User
      .findOne({ 'username': username })
      .exec((err, result) => {
        if (result) {
          callback(null, result);
        } else {
          callback(err);
        }
      });
  },

  function(userid, callback) {

    // find user's feed
    Feed
      .find({})
      // .populate('user', {_id: userid._id})  <== this one also doesn't work
      .populate({
        path: 'user',
        match: { '_id': { $in: userid._id } }
      })
      .exec(callback);
  }
], function(err, docs) {
  if (err) {
    return next(err);
  }

  console.log(docs);
});

使用上面的代码,我得到了所有的提要,而且查询选项似乎根本不起作用,我做错了吗?

任何帮助将不胜感激。

【问题讨论】:

    标签: javascript node.js mongodb mongoose async.js


    【解决方案1】:

    _id 的值已经存储在您甚至填充“之前”的"user" 属性中时,不确定为什么要匹配“之后”填充。

    因此,它实际上只是对.find() 的简单“查询”条件:

    async.waterfall([
      (callback) =>
        User.findOne({ 'username': username }).exec(callback),
    
      (user, callback) => {
        if (!user) callback(new Error('not found'));  // throw here if not found
        // find user's feed
        Feed
          .find({ user: user._id })
          .populate('user')
          .exec(callback);
      }
    ], function(err, docs) {
      if (err) {
        return next(err);
      }
    
      console.log(docs);
    });
    

    当然要记住 .findOne() 正在返回整个文档,因此您只需要在新查询中使用 _id 属性。另请注意,初始瀑布函数中的“杂耍”不是必需的。如果有错误,那么它将“快速失败”到结束回调,或者通过它不是的结果。改为将“未找到”延迟到下一个方法。

    当然这真的没有必要,因为"Promises" 已经存在了一段时间,你真的应该使用它们:

    User.findOne({ "username": username })
     .then( user => Feed.find({ "user": user._id }).populate('user') )
     .then( feeds => /* do something */ )
     .catch(err => /* do something with any error */)
    

    或者确实在 MongoDB 支持的地方使用 $lookup

    User.aggregate([
      { "$match": { "username": username } },
      { "$lookup": {
        "from": Feed.collection.name,
        "localField": "_id",
        "foreignField": "user",
        "as": "feeds"
      }}
    ]).then( user => /* User with feeds in array /* )
    

    这在输出上有些不同,您实际上可以通过一些操作将其更改为看起来相同,但这应该可以让您大致了解。

    重要的是,让服务器进行加入而不是发出多个请求通常会更好,这至少会增加延迟。

    【讨论】:

    • 非常感谢,现在可以使用了。正如你所说,我将代码更改为使用 Promises。
    猜你喜欢
    • 2013-08-13
    • 2016-01-20
    • 2014-10-31
    • 2018-11-13
    • 2020-09-06
    • 2015-09-03
    • 1970-01-01
    • 2015-07-18
    相关资源
    最近更新 更多