如何在mongoose中加入两个集合

时间:2016-04-23 02:00:39

标签: node.js mongodb mongoose 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
    }
});

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

任何人都知道如何实现这样的目标?

4 个答案:

答案 0 :(得分:17)

从版本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
});

答案 1 :(得分:9)

您不希望.populate()在这里,而是您需要两个查询,其中第一个匹配Student个对象以获取_id值,第二个将使用{{3为那些“学生”匹配相应的WorksnapsTimeEntry项目。

使用$in只是为了避免一些缩进蠕变:

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并返回“所有内容”,然后使用“匹配”查询选项过滤掉null的{​​{1}}个结果:

.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 }); “等属性,并且不需要其他查询。

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

答案 2 :(得分:0)

为时已晚,但会帮助许多开发人员。 验证方式

<块引用>

"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()

产品模型架构

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

类别模型架构

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

答案 3 :(得分:0)

试试这个 code 在猫鼬中加入两个集合

Mongoose 加入两个集合创建架构

const { Schema, model} = require("mongoose");

const UserSchema = new Schema({
   name:{
      type: String,
      required: true
   },
   email:{
      type: String,
      required: true
   },
   posts:[{
      type: Schema.Types.ObjectId, ref: "Post"
   }]
});


const PostSchema = new Schema({
   title: String,
   desc: String,
   User: {type: Schema.Tpes.ObjectId, ref: "User"}
});

export const Post = model("Post", PostSchema);
export const User = model("User", UserSchema);

然后

try {
   const user = User.create({
      name:"Robert Look",
      email: "phpcodingstuff@gmail.com"
   })

   try {
      const post1 = Post.create({
         title: "This is a first post",
         desc: "this a a first description"
         user: User._id // assign the _id from the user
      });
   } catch (err) {
      console.log(err.message)
   }
} catch (err) {
   console.log(err.message)
}

阅读模型

User.findOne({
   name: "Robert Look"
}).populate('posts').exec((err, user) =>{
   if(err){
      console.log(err)
   }else{
      console.log(users.posts[0].desc)
   }
});

结论 我们在上面看到了如何使用 populate 我们还看到了如何使用 joining two documents in mongoose (MongoDB),如果您正确编写查询,那么您将获得一个好的结果或您的 JSON。