如何在猫鼬中加入两个集合

新手上路,请多包涵

我有两个模式定义如下:

 var WorksnapsTimeEntry = BaseSchema.extend({
 student: {
     type: Schema.ObjectId,
     ref: 'Student'
 },
 timeEntries: {
     type: Object
 }
 });

var StudentSchema = BaseSchema.extend({
firstName: {
    type: String,
    trim: true,
    default: ''
    // validate: [validateLocalStrategyProperty, 'Please fill in your first name']
},
lastName: {
    type: String,
    trim: true,
    default: ''
    // validate: [validateLocalStrategyProperty, 'Please fill in your last name']
},
displayName: {
    type: String,
    trim: true
},
municipality: {
    type: String
    }
});

我想遍历每个学生并显示它的时间条目。到目前为止,我的这段代码显然不正确,因为我仍然不知道如何加入 WorksnapTimeEntry 模式表。

 Student.find({ status: 'student' })
        .populate('student')
        .exec(function (err, students) {
            if (err) {
                return res.status(400).send({
                    message: errorHandler.getErrorMessage(err)
                });
            }
            _.forEach(students, function (student) {
               // show student with his time entries....
            });
            res.json(students);
        });

任何人都知道我该如何实现这一目标?

原文由 Lulzim 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 632
2 个回答

您不希望 .populate() 在这里,而是您想要两个查询,其中第一个与 Student 对象匹配以获取 _id 值, $in 以匹配那些“学生”的相应 WorksnapsTimeEntry 项目。

使用 async.waterfall 只是为了避免一些缩进蠕变:

 async.waterfall(
    [
        function(callback) {
          Student.find({ "status": "student" },{ "_id": 1 },callback);
        },
        function(students,callback) {
            WorksnapsTimeEntry.find({
                "student": { "$in": students.map(function(el) {
                    return el._id
                })
            },callback);
        }
    ],
    function(err,results) {
       if (err) {
          // do something
       } else {
          // results are the matching entries
       }
    }
)

如果你真的必须,那么你可以在第二个查询中 .populate("student") 从另一个表中获取填充的项目。

相反的情况是查询 WorksnapsTimeEntry 并返回“一切”,然后使用“匹配”查询选项过滤掉来自 .populate() 的任何 null 结果:

 WorksnapsTimeEntry.find().populate({
    "path": "student",
    "match": { "status": "student" }
}).exec(function(err,entries) {
   // Now client side filter un-matched results
   entries = entries.filter(function(entry) {
       return entry.student != null;
   });
   // Anything not populated by the query condition is now removed
});

所以这不是一个可取的操作,因为“数据库”没有过滤可能的大部分结果。

除非您有充分的理由不这样做,否则您可能“应该”“嵌入”数据。这样,像 "status 之类的属性已经在集合中可用,并且不需要额外的查询。

如果您使用的是像 MongoDB 这样的 NoSQL 解决方案,您应该接受它的概念,而不是坚持关系设计原则。如果您一直在进行关系建模,那么您不妨使用关系数据库,因为您不会从具有其他处理方式的解决方案中获得任何好处。

原文由 Blakes Seven 发布,翻译遵循 CC BY-SA 3.0 许可协议

从 3.2 版本开始,您可以在聚合管道中使用 $lookup 来执行左外连接。

 Student.aggregate([{
    $lookup: {
        from: "worksnapsTimeEntries", // collection name in db
        localField: "_id",
        foreignField: "student",
        as: "worksnapsTimeEntries"
    }
}]).exec(function(err, students) {
    // students contain WorksnapsTimeEntries
});

原文由 Talha Awan 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题