在猫鼬模型中将对象添加到人口
Posted
技术标签:
【中文标题】在猫鼬模型中将对象添加到人口【英文标题】:Add to an object to Population in a Mongoose Model 【发布时间】:2015-09-10 08:20:57 【问题描述】:我是 Mongoose 的新手,我对人群有所了解。我的架构看起来像...
var ProjectSchema = new Schema(
name:
type: String,
default: '',
required: 'Please fill Project name',
trim: true
,
created:
type: Date,
default: Date.now
,
topics: [
type: Schema.ObjectId,
ref: 'Topic'
]
);
当我查询项目时,我使用 .populate('topics') 并且它工作正常。填充项目时,主题属性包含实际对象而不是引用。
附:该主题没有项目参考(我发现很难在 MongoDB 中维护互惠关系)。
我的问题是:当我想将主题对象添加到项目中时。我是添加 ObjectId 还是对象本身?
【问题讨论】:
【参考方案1】:我看到了这个问题和给出的答案,但我认为它并不能真正解释你的问题,所以我认为这里有一些有价值的东西。
正如在提供的架构中所展示的那样,“主题”属性是一个“引用数组”,这基本上意味着它将持有一个“引用”(或本质上是一个 ObjectId
值)到另一个文档中收藏。正如您应该知道的,猫鼬“模式”定义将它与该对象所在的“关联”模型联系起来。
提出的问题是“我是推动对象,还是只推动_id
值”,这本身就引发了一些关于“你真正想在这里做什么?”的问题。
最后,以下面的代码示例为例(假设模型和模式都已定义):
var project = new Project( "name": "something" );
var topic = new Topic( "name": "something" );
project.topics.push(topic); // this actually just adds _id since it's a ref
// More code to save topic and project in their colllections
因此,根据代码中的注释,即使您要求猫鼬“推送”整个“对象”,猫鼬实际上也只会将“_id”值添加到父文档中。它只是通过提供给模型的模式接口来解决“这就是你想要做的”。在代码中真的不难做到,但只是为了让您了解底层机制。
您可以交替地从创建的对象中“只使用_id
值”(在它为安全起见保存之后),并通过类似的方式将其添加到数组中。结果大致相同:
var project = new Project( "name": "something" );
// Yes we saved the Project object, but later...
var topic = new Topic( "name": "something" );
topic.save(function(err,topic)
if (err) throw (err): // or better handling
project.topics.push(topic._id); // explicit _id
);
该方法很好,当然前提是您在处理Project
和Topic
时以某种形式实际拥有“内存中的对象”以及适当的数据。
另一方面,让我们假设 Project
表示集合中的一个对象,尽管您知道它是 _id
值或其他“唯一”表示属性,但实际上并未从该对象数据加载数据库通过.findOne()
类型的操作或类似的操作。
然后让我们假设您没有任何Project
模型数据驻留在内存中。那么如何添加新主题呢?
这就是 MongoDB 的本地运算符发挥作用的地方。特别是 $push
,它当然类似于 javascript 中的 .push()
数组运算符,但具有特定的“服务器端”操作。
如前所述,您没有加载 Project
模型数据,但您希望通过将所需的 Topic
对象“推送”到您的 Project
中定义的对象来修改存储中的特定 Project
项目对象的标识符集合:
var topic = new Topic( "name": "something" );
topic.save(function(err,topic)
if (err) throw err; // or much better handling
Project.update(
"_id": projectId ,
"$push":
"topics": topic._id
,
function(err,numAffected)
// and handle responses here
);
)
“更新”机制可以是 .findOneAndUpdate()
甚至是 .findByIdAndUpdate()
,只要您认为合适(这些方法都默认返回修改后的对象,而 .update()
没有)到您想要实现的结果操作在这里。
与先前方法的主要区别在于,由于要修改的 Project
的对象不驻留在应用程序代码的内存中,因此您使用这些方法只是在服务器上修改它。这可能是一件“好事”,因为您需要“加载”这些数据只是为了进行修改。 MongoDB 运算符允许您在不先加载的情况下$push
数组内容。
这种方法确实是高事务系统“并发更新”的最佳方法。原因是“无法保证”在您的应用程序中的.findOne()
或类似操作与最终.save()
操作的修改之间,即在这些操作之间发生的服务器存储上“没有数据已被更改”。
$push
运算符“确保”在服务器上修改的数据在执行时保持“原样”,当然还会添加您添加到数组中的新数据。
这里另一个明显的事情是,由于该操作使用本地 MongoDB 运算符来实现此效率,因此 mongoose Schema 规则是基于基础的。因此,您当然不能只是将整个“主题”对象“推入”数组中,当然不能以存储中的“整个”主题对象结束:
Project.update(
"_id": projectId ,
"$push":
"topics": topic // Oops, now that would store the whole object!
,
function(err,numAffected)
// and handle responses here
);
这本质上是“向数组添加对象引用”和“向数组添加'对象'”之间的区别。这取决于使用的方法和您实际选择的“效率”方法。
希望这对您自己和可能偶然发现您提出的同一主题的其他人有用。
【讨论】:
优秀的答案。正是我需要的。感谢您的澄清! 嗨,基拉。你能加入这个聊天室吗? chat.***.com/rooms/95345 @BlakesSeven 你能把你的电子邮件地址发给我吗?在这里,或者我的电子邮件:dmitrii.shevchenko@gmail.com — 我想邀请你加入我创建的 MongoDB Slack 团队。【参考方案2】:如果主题架构具有项目引用,则只需保存 ObjectId,因为将引用保存到其他文档的工作方式与通常保存属性的方式相同,只需分配 _id 值:
var topicSchema = Schema(
_author : type: Schema.ObjectId, ref: 'Project' ,
title : String
);
var Topic = mongoose.model('Topic', topicSchema);
var Project = mongoose.model('Project', projectSchema);
var my_project = new Project( name: 'Test Project' );
my_project.save(function (err)
if (err) return handleError(err);
var topic1 = new Topic(
title: "My Topic",
_author: my_project._id // assign the _id from the project
);
topic1.save(function (err)
if (err) return handleError(err);
// thats it!
);
);
请参阅 docs 了解更多详情。
-- 编辑--
如果主题架构没有项目引用,那么您需要推送对象本身:
var Topic = mongoose.model('Topic', topicSchema);
var Project = mongoose.model('Project', projectSchema);
var my_project = new Project( name: 'Test Project' );
var topic1 = new Topic(
title: "My Topic"
);
my_project.stories.push(topic1);
my_project.save(callback);
【讨论】:
你在这里做了几乎相反的事情。您正在将项目的引用存储在主题中,而我正在将主题列表存储到项目中。问题是在前端,使用“填充”,项目带有嵌入的完整主题实例。您是否建议我只在包含对象的列表中添加 ID? @MikeM 假设Topic
模式也有一个Project
参考。你能用实际的主题架构更新你的问题吗?以上是关于在猫鼬模型中将对象添加到人口的主要内容,如果未能解决你的问题,请参考以下文章