猫鼬:填充人口稠密的土地

时间:2011-12-17 09:53:03

标签: mongodb node.js mongoose populate

我正在使用MongoDB作为我的应用程序的日志管理器,然后同步移动客户端。我在NodeJS中设置了这个模型:

var UserArticle = new Schema({
    date: { type: Number, default: Math.round((new Date()).getTime() / 1000) }, //Timestamp!
    user: [{type: Schema.ObjectId, ref: "User"}],
    article: [{type: Schema.ObjectId, ref: "Article"}],
    place: Number,    
    read: Number,     
    starred: Number,   
    source: String
});
mongoose.model("UserArticle",UserArticle);

var Log = new Schema({
    user: [{type: Schema.ObjectId, ref: "User"}],
    action: Number, // O => Insert, 1 => Update, 2 => Delete
    uarticle: [{type: Schema.ObjectId, ref: "UserArticle"}],
    timestamp: { type: Number, default: Math.round((new Date()).getTime() / 1000) }
});
mongoose.model("Log",Log);

当我想要检索日志时,我使用以下代码:


var log = mongoose.model('Log');
log
.where("user", req.session.user)
.desc("timestamp")
.populate("uarticle")
.populate("uarticle.article")
.run(function (err, articles) {
if (err) {
    console.log(err);
        res.send(500);
    return;
}
res.json(articles);

正如您所看到的,我希望mongoose从Log集合中填充“uarticle”字段,然后,我想填充UserArticle(“uarticle”)的“article”字段。

但是,使用此代码,Mongoose仅使用UserArticle模型填充“uarticle”,而不是uarticle中的文章字段。

是否可以使用Mongoose和populate()来完成它,或者我应该做些什么呢?

谢谢,

5 个答案:

答案 0 :(得分:15)

根据我在文档中检查的内容以及我从您那里听到的内容,这无法实现,但您可以在回调函数中自己填充“uarticle.article”文档。

但是我想指出另一个我认为更重要的方面。您在集合A中有文档引用集合B,在集合B的文档中,您有另外引用集合C中的文档。

你要么做错了(我指的是数据库结构),要么你应该在这里使用像MySQL这样的关系数据库。 MongoDB的强大之处在于您可以在文档中嵌入更多信息,因此必须进行较少的查询(将您的数据放在一个集合中)。虽然引用某些内容是可以的,但是有一个引用然后另一个引用似乎并不像你在这里充分利用了MongoDB。

也许您想分享您的情况和数据库结构,以便我们为您提供更多帮助。

答案 1 :(得分:2)

我遇到了同样的问题,但经过几个小时的努力,我找到了解决方案。它可以不使用任何外部插件:)

    applicantListToExport: function (query, callback) {
      this
       .find(query).select({'advtId': 0})
       .populate({
          path: 'influId',
          model: 'influencer',
          select: { '_id': 1,'user':1},
          populate: {
            path: 'userid',
            model: 'User'
          }
       })
     .populate('campaignId',{'campaignTitle':1})
     .exec(callback);
    }

答案 2 :(得分:0)

如下:

populate_deep = function(type, instance, complete, seen)
{
  if (!seen)
    seen = {};
  if (seen[instance._id])
  {
    complete();
    return;
  }
  seen[instance._id] = true;
  // use meta util to get all "references" from the schema
  var refs = meta.get_references(meta.schema(type));
  if (!refs)
  {
    complete();
    return;
  }
  var opts = [];
  for (var i=0; i<refs.length; i++)
    opts.push({path: refs[i].name, model: refs[i].ref});
  mongoose.model(type).populate(instance, opts, function(err,o){
    utils.forEach(refs, function (ref, next) {
      if (ref.is_array)
        utils.forEach(o[ref.name], function (v, lnext) {
          populate_deep(ref.ref_type, v, lnext, seen);
        }, next);
      else
        populate_deep(ref.ref_type, o[ref.name], next, seen);
    }, complete);
  });
}

meta utils很粗糙...想要src?

答案 3 :(得分:0)

猫鼬v5.5.5似乎允许在已填充的文档上进行填充。

您甚至可以提供一个包含多个字段的数组以填充到填充的文档中!

var batch = await mstsBatchModel.findOne({_id: req.body.batchId})
  .populate({path: 'loggedInUser', select: 'fname lname', model: 'userModel'})
  .populate({path: 'invoiceIdArray', model: 'invoiceModel', 
     populate: [
       {path: 'updatedBy', select: 'fname lname', model: 'userModel'},
       {path: 'createdBy', select: 'fname lname', model: 'userModel'},
       {path: 'aircraftId', select: 'tailNum', model: 'aircraftModel'}
     ]});

答案 4 :(得分:0)

或者您可以简单地将obj传递给填充对象:

const myFilterObj = {};
const populateObj = {
                path: "parentFileds",
                populate: {
                    path: "childFileds",
                    select: "childFiledsToSelect"
                },
                select: "parentFiledsToSelect"
               };
Model.find(myFilterObj)
     .populate(populateObj).exec((err, data) => console.log(data) );