3

我是 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') 并且它工作正常。填充项目时,主题属性包含实际对象而不是引用。

PS The Topic 没有项目参考(我发现很难在 MongoDB 中维护互惠关系)。

我的问题是:当我想向项目添加主题对象时。我是添加 ObjectId 还是对象本身?

4

2 回答 2

3

我看到了这个问题和给出的答案,但我认为它并不能真正解释你的问题,所以我认为这里有一些有价值的东西。

正如在提供的架构中所展示的那样,“主题”属性是一个“引用数组”,这基本上意味着它将持有对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
});

该方法一切都很好,当然前提是通过某种形式或其他形式,您在处理两者ProjectTopic具有适当数据时实际上拥有“内存中的对象”。

另一方面,让我们假设它Project表示集合中的一个对象,尽管您知道它是_id值或其他“唯一”表示属性,但该对象数据实际上并未通过.findOne()操作类型或类似类型从数据库中加载。

然后让我们假设您没有任何Project模型数据驻留在内存中。那么如何添加新主题呢?

这就是 MongoDB 的本地运算符发挥作用的地方。特别是$push它当然类似于.push()JavaScript 中的数组运算符,但具有特定的“服务器端”操作。

如前所述,您没有加载模型数据,但您希望通过将所需对象“推送”到对象集合中由其标识符定义的对象Project来修改存储中的特定项目:ProjectTopicProject

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
        }
    );

这本质上是“向数组添加对象引用”和“向数组添加'对象'”之间的区别。这取决于使用的方法和您实际选择的“效率”方法。

希望这对您自己和可能偶然发现您提出的同一主题的其他人有用。

于 2015-06-24T11:48:37.660 回答
1

如果主题架构具有项目引用,则只需要保存 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!
    });
});

有关更多详细信息,请参阅文档


--编辑--

如果主题架构没有项目引用,那么您需要推送对象本身:

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);
于 2015-06-24T08:32:41.117 回答