Mongodb 猫鼬:填充填充的字段

Mongodb 猫鼬:填充填充的字段,mongodb,node.js,mongoose,populate,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: Sc

我使用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从日志集合填充“uarticle”字段,然后,我希望填充UserArticle(“uarticle”)的“article”字段

但是,使用这段代码,Mongoose只使用UserArticle模型填充“uarticle”,而不填充uarticle中的article字段

是否可以使用Mongoose和populate()完成它,或者我应该做其他事情


谢谢,

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

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

要么你做得不对(我指的是数据库结构),要么你应该在这里使用关系数据库,比如MySQL。MongoDB的强大之处在于,您可以在文档中嵌入更多信息,因此需要进行更少的查询(将数据放在单个集合中)。虽然引用某个东西是可以的,但是有一个引用,然后又有另一个引用似乎并没有充分利用MongoDB


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

以下内容如何:

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);
  });
}
populate\u deep=函数(类型、实例、完成、查看)
{
如果(!看到)
seed={};
如果(参见[实例]\u id])
{
完全();
返回;
}
seed[instance.\u id]=true;
//使用meta-util从模式中获取所有“引用”
var refs=meta.get_引用(meta.schema(type));
如果(!参考)
{
完全();
返回;
}
var opts=[];
对于(var i=0;i您可以使用插件来完成此操作。用法:

User.find({}, function (err, users) {
   User.deepPopulate(users, 'uarticle.article', function (err, users) {
      // now each user document includes uarticle and each uarticle includes article
   })
})

免责声明:我是该插件的作者。

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


Mongoose 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'}
     ]});

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

constmyfilterobj={};
常数populateObj={
路径:“parentFileds”,
填充:{
路径:“子文件”,
选择:“childFiledsToSelect”
},
选择:“parentFiledsToSelect”
};
Model.find(myFilterObj)
.populate(populateObj).exec((err,data)=>console.log(data));

Logs集合是唯一一个有奇怪引用的集合,我只是想要,因为其他集合只有一个引用(以避免重复多次相同的数据)。我认为,为了避免使用大量信息,我不会将其填充为“uarticle”客户端会请求获取文章的详细信息,只是为了让事情简单快速。您能提供更多关于您的答案的详细信息吗?我读对了吗,应该检查哪怕只有一个引用。我只是刚开始使用mongodb。毕竟,很多关系表只有一个外键。是否嵌入了documents优于填充ObjectId引用?这实际上取决于项目的结构,有时您甚至可能需要复制数据(嵌入)为了提高速度,其他时候您可能需要引用它,因为只有在特定条件下才会查询该数据。我遇到了相同的问题,引用嵌入到数组->myList:[{mid:{type:Schema.ObjectId,'ref':'OtherModel'},meta:[String]}。当我尝试填充('myList.mid')时,会产生以下错误…TypeError:无法调用未定义的方法“path”
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'}
     ]});