Mongoose中的模式嵌套

36

我如何将一个模式添加到另一个模式中?以下代码似乎无效:

var UserSchema = new Schema({
    name        : String,
    app_key     : String,
    app_secret  : String
})



var TaskSchema = new Schema({
    name            : String,
    lastPerformed   : Date,
    folder          : String,
    user            : UserSchema
})

我查看了网站,它展示了如何为数组声明,但没有说明如何声明单个变量。

谢谢


你是在两个集合之间进行连接还是想将它们存储在任务之上? - Jamund Ferguson
4个回答

47

有几种方法可以做到这一点。最简单的方法只需:

var TaskSchema = new Schema({
    name            : String,
    lastPerformed   : Date,
    folder          : String,
    user            : Schema.ObjectId
});

然后您只需要确保您的应用程序编写该ID并在必要时在查询中使用它来获取“相关”数据。

当按用户ID搜索任务时,这很好,但按任务ID查询用户时会更加麻烦:

// Get tasks with user id
Task.find({user: user_id}, function(err, tasks) {...});

// Get user from task id
Task.findById(id, function(err, task) {
  User.findById(task.user, function(err, user) {
    // do stuff with user
  }
}

另一种方法是利用Mongoose的populate特性来简化您的查询。为了实现这个目的,您可以按照以下步骤进行操作:

var UserSchema = new Schema({
    name        : String,
    app_key     : String,
    app_secret  : String,
    tasks       : [{type: Schema.ObjectId, ref: 'Task'}] // assuming you name your model Task
});

var TaskSchema = new Schema({
    name            : String,
    lastPerformed   : Date,
    folder          : String,
    user            : {type: Schema.ObjectId, ref: 'User'} // assuming you name your model User
});

通过这种方式,您可以查询所有用户,包括他们的任务数组:

User.find({}).populate('tasks').run(function(err, users) {
  // do something
});

当然,这意味着需要在两个地方都维护id。如果这让你感到困扰,最好还是坚持第一种方法,并逐渐习惯编写更复杂(但仍然足够简单)的查询。


谢谢你详细的回复。我还有一个问题,但也许我应该创建一个新的问题。 - 0xSina
2
".run()" 被替换成 ".exec()",因为它更合适。 - Oliver Salzburg
另一个链接,使用populate,可能也会对您有所帮助。 - AbdulMomen عبدالمؤمن
类型:Schema.Types.ObjectId - M22

15

从4.2.0版本开始,Mongoose支持单个子文档。

来自文档

var childSchema = new Schema({ name: 'string' });

var parentSchema = new Schema({
  // Array of subdocuments
  children: [childSchema],
  // Single nested subdocuments. Caveat: single nested subdocs only work
  // in mongoose >= 4.2.0
  child: childSchema
});

11

这个简单的解决方案怎么样?

var TaskSchema = new Schema({
    name            : String,
    lastPerformed   : Date,
    folder          : String,
    user            : {
        name        : String,
        app_key     : String,
        app_secret  : String
    }
 })

9
这是否会取消直接查询用户的能力,同时还可能导致用户对象在多个任务中被重复复制?如果您要将数据模型扁平化为一个结构,我认为您希望UserSchema成为tasks的父级而不是反过来。 - VictorB
1
使代码看起来凌乱。因此希望模式在模式内部。 - Flyn Sequeira
这不是适用于使用多个或大型嵌入式模式的模式的可扩展解决方案。我认为 OP(和我)想要非平凡的解决方案。 - Furkan Toprak

0
var UserSchema = new Schema({
    name        : String,
    app_key     : String,
    app_secret  : String
});
var TaskSchema = new Schema({
name            : String,
lastPerformed   : Date,
folder          : String,
user            :{
type            : mongoose.Schema.Types.ObjectId,
ref             : 'User', // Reference the 'User' model
} 
});
const User=mongoose.model('User',UserSchema);
const Tasks=mongoose.model('Tasks',Taskschema);

TaskSchema中的user字段被设置为对User模型的引用。通过使用mongoose.Schema.Types.ObjectId作为数据类型,您指示user字段将存储User文档的ObjectId

ref: 'User'属性表示user字段引用了User模型。当保存Task文档时,您需要提供现有User文档的_id(ObjectId),以将任务链接到适当的用户。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接