猫鼬和人口嵌套

时间:2015-03-12 07:37:10

标签: javascript node.js mongodb mongoose

我已经阅读了一些关于Mongoose的内容,因为它无法管理嵌套群体。

事实是,当我执行findOne()调用时,返回的对象能够使用populate函数。但它似乎没有工作......

你能帮我处理2级填充吗?多个查询不是问题。

这是我的CoffeeScript代码:

Agency.findOne({"agencyUsers": idUser}, '_id agencyUsers agencySites agencyDevices').populate([
      {path: 'agencyUsers', match: { actif: true}, select: '_id userPin'},
      {path: 'agencySites', match: { actif: true}, select: '_id siteName siteBuildings siteSectors siteUsers'},
      {path: 'agencyDevices', match: { actif: true}, select: '_id deviceMac'}
    ])
    .exec((err, res)=>
      if err
        deffered.reject err
      else
        res.populate('agencySites.siteBuildings', (errs, ress)=>
          deffered.resolve(res)
        )
    )

编辑:

根据我们需要在站点(代理商)中填充建筑物的事实

AgencySchema:

{
  agencyName: String,
  agencyStreet: String,
  agencyCity: String,
  agencyPostal: String,
  agencyCountry: String,
  agencyPhone: String,
  agencyFax: String,
  agencyMail: String,
  agencySiret: String,
  agencyAgencies: [
    { type: Schema.ObjectId, ref: 'Agency' }
  ],
  agencyDevices: [
    { type: Schema.ObjectId, ref: 'Device' }
  ],
  agencySites: [
    { type: Schema.ObjectId, ref: 'Site' }
  ],
  agencyUsers: [
    { type: Schema.ObjectId, ref: 'User' }
  ],
  agencyModules: [
    { type: Schema.ObjectId, ref: 'Module' }
  ],
  actif: {type: Boolean, default: true},
  actif_date: { type: Date, default: null },
  creation_date: { type: Date, default: Date.now },
  edit_date: { type: Date, default: null }
}

网站schéma:

{
  siteName: String,
  siteStreet: String,
  siteCity: String,
  sitePostal: String,
  siteCountry: String,
  sitePhone: String,
  siteMail: String,
  siteAgencies: [
    { type: Schema.ObjectId, ref: 'Agency' }
  ],
  siteUsers: [
    { type: Schema.ObjectId, ref: 'User' }
  ],
  siteSectors: [
    { type: Schema.ObjectId, ref: 'Sector' }
  ],
  siteBuildings: [
    { type: Schema.ObjectId, ref: 'Building' }
  ],
  siteModules: [
    { type: Schema.ObjectId, ref: 'Module' }
  ],
  actif: {type: Boolean, default: true},
  actif_date: { type: Date, default: null },
  creation_date: { type: Date, default: Date.now },
  edit_date: { type: Date, default: null }
}

建筑架构:

{
  buildingName: String,
  buildingFloors: [
    { type: Schema.ObjectId, ref: 'Floor' }
  ],
  actif: {type: Boolean, default: true},
  actif_date: { type: Date, default: null },
  creation_date: { type: Date, default: Date.now },
  edit_date: { type: Date, default: null }
}

3 个答案:

答案 0 :(得分:1)

仅限JavaScript响应。你执行translation:)

在这种情况下,这并没有真正起作用,因为实际上这些原因让我感到懊恼,但为了做你想做的事,你需要打电话给"模型"形式为.populate()而不是:

Agency.findOne({"agencyUsers": idUser}, '_id agencyUsers agencySites agencyDevices')
    .populate([
      { "path": "agencyUsers", "match": { "actif": true}, "select": "_id userPin" },
      {
        "path": "agencySites", 
        "match": { "actif": true }, 
        "select": "_id siteName siteBuildings siteSectors siteUsers"
      },
      {
        "path": "agencyDevices", 
        "match": { "actif": true}, 
        "select": "_id deviceMac"
      }
]).exec(function(err,doc) {
    if (err) {
        deffered.reject(err);
    } else {
        async.waterfall([
           function(callback) {
               Agency.populate( doc, { "path": "agencyAgencies.siteAgencies" },callback);
           },
           function(doc,callback) {
               User.populate( doc, { "path": "agencyAgencies.siteUsers" },callback);
           },
           function(doc,callback) {
               Sector.populate( doc, { "path": "agencyAgencies.siteSectors" },callback);
           },
           function(doc,callback) {
               Building.populate( doc, { "path": "agencyAgencies.siteBuildings" },callback);
           },
           function(doc,callback) {
               Module.populate( doc, { "path": { "agencyAgencies.siteModules" },callback);
           }
        ],function(err,res) {
           if (err) {
               deffered.reject(err);
           } else {
               Floor.populate(res,{ "path": "agencyAgencies.siteBuildings.buildingFloors" },function(err,res) {
                   if (err) {
                       deffered.reject(err);
                   } else {
                       deffered.resolve(res);
                   }
               });
           }
        });
    }
});

尽管我使用"async.waterfall",但只是试图避免"缩进蠕变"每次嵌入式迭代。

因此,您可以看到实际上有必要以这种方式为每种特定的模型类型调用.populate()。还有一个必要的呼叫在"再次嵌套" "建筑"模型参考也需要在""之后调用。文档已填充。所以它就是"调用堆栈"这是你之前提到的嵌套填充问题的一部分。

通过如此繁重的引用,您可以考虑重新设计架构和/或嵌入大量此类数据。它看起来非常"关系"因此,你可能不会通过这种方式获得完整的MongoDB好处。

答案 1 :(得分:1)

@Neil Lunn的回答是正确的,我只想对co有所了解,因为你有兴趣清理你的代码:

co(function* {
  var agency = yield Agency.findOne({'agencyUsers': idUser}, '_id agencyUsers agencySites agencyDevices')
    .populate(
      { 'path': 'agencyUsers', 'match': { 'actif': true }, 'select': '_id userPin' },
      { 'path': 'agencySites', 'match': { 'actif': true }, 'select': '_id siteName siteBuildings siteSectors siteUsers' },
      { 'path': 'agencyDevices', 'match': { 'actif': true }, 'select': '_id deviceMac' })

  agency = yield Agency.populate(agency, 'agencyAgencies.siteAgencies')
  agency = yield User.populate(agency, 'agencyAgencies.siteUsers')
  agency = yield Sector.populate(agency, 'agencyAgencies.siteSectors')
  agency = yield Building.populate(agency, 'agencyAgencies.siteBuildings')
  agency = yield Module.populate(agency, 'agencyAgencies.siteModules')

  return agency
})
.then(agency => {
   Floor.populate(agency, 'agencyAgencies.siteBuildings.buildingFloors', function (err, res) {
     if (err)
       deferred.reject(err)

     deferred.resolve(agency)
   })
})
.catch(deferred.reject)

答案 2 :(得分:1)

从版本^ 4.1.x开始,深层人口实际上是猫鼬中的事物,因此执行类似操作是有效的:-

Post.find({}).populate({
   path: 'user',
   select: 'id name',
   populate: {
      path: 'friends',
      select: 'id name,'
      populate: {
          path: 'friends',
          select: 'id name',
      }
   }
})

populate可以将一个对象或对象数组作为值,这意味着您可以填充引用不同集合的兄弟属性。 有关更多信息,请查看此帖子:http://frontendcollisionblog.com/mongodb/2016/01/24/mongoose-populate.html