如何在mongoose中加入两个集合

His*_*ija 8 mongoose mongodb node.js mongodb-query

我有两个Schema定义如下:

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
    }
});
Run Code Online (Sandbox Code Playgroud)

我想循环通过每个学生并显示它的时间条目.到目前为止,我有这个代码,显然不对,因为我还不知道如何加入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);
        });
Run Code Online (Sandbox Code Playgroud)

谁知道我怎么做到这样的事情?

Tal*_*wan 23

从版本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
});
Run Code Online (Sandbox Code Playgroud)


Bla*_*ven 10

你不想.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
       }
    }
)
Run Code Online (Sandbox Code Playgroud)

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

相反的情况是查询WorksnapsTimeEntry并返回"所有内容",然后使用"匹配"查询选项过滤掉任何null结果.populate():

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
});
Run Code Online (Sandbox Code Playgroud)

因此,这不是一个理想的行动,因为"数据库"不会过滤可能的大部分结果.

除非你有充分的理由不这样做,否则你可能"应该""嵌入"数据.这样,诸如"status"已经在集合上可用的属性和其他查询不是必需的.

如果您正在使用像MongoDB这样的NoSQL解决方案,那么您应该接受它的概念,而不是坚持关系设计原则.如果您一直在建模关系,那么您也可以使用关系数据库,因为您将无法从具有其他方法来处理该解决方案的解决方案中获得任何好处.


Muh*_*zad 5

虽然已经晚了,但会对许多开发人员有所帮助。已验证

“mongodb”:“^3.6.2”,“猫鼬”:“^5.10.8”,

在 mongoose 中加入两个集合

ProductModel.find({} , (err,records)=>{
    if(records)
        //reurn records
    else
        // throw new Error('xyz')

})
.populate('category','name') //select only category name joined collection
//.populate('category') // Select all detail
.skip(0).limit(20)
//.sort(createdAt : '-1')
.exec()
Run Code Online (Sandbox Code Playgroud)

产品模型架构

const CustomSchema = new Schema({
    category:{
        type: Schema.ObjectId,
        ref: 'Category'
    },
     ...
}, {timestamps:true}, {collection: 'products'});
module.exports = model('Product',CustomSchema)
Run Code Online (Sandbox Code Playgroud)

类别模型架构

const CustomSchema = new Schema({
 
    name:   { type: String, required:true },
    ...
}, {collection: 'categories'});
module.exports = model('Category',CustomSchema)
Run Code Online (Sandbox Code Playgroud)