添加到Mongoose模型中的群体的对象

时间:2015-06-24 08:20:36

标签: mongoose mongoose-populate

我是Mongoose的新手,并且围绕着人群。我的Schema看起来像......

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'),它运行正常。填充项目时,topics属性包含实际对象而不是引用。

P.S。主题没有项目引用(我发现很难在MongoDB中维护resiprocal关系)。

我的问题是:当我想将一个主题对象添加到项目中时。我是否添加了ObjectId或对象本身?

2 个答案:

答案 0 :(得分:3)

我看到了这个问题并给出了答案,但我认为它并没有真正解释你的要求,所以我觉得这里有些值得的。

正如在提供的模式中所证明的那样,“topics”属性是一个“引用的数组”,这基本上意味着它将保存一个“引用”(或基本上是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

因此,根据代码中的注释,mongoose实际上只会将“_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当然类似于JavaScript中的.push()数组运算符,但具有特定的“服务器端”操作。

如前所述,您没有加载Project模型数据,但是您希望通过将所需的Project对象“推送”到某个内容来修改存储中的特定Topic项目在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
        }
    );

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

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

答案 1 :(得分:1)

如果主题架构具有项目引用,则只需要保存ObjectId,因为将refs保存到其他文档的工作方式与通常保存属性的方式相同,只需指定_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

- 编辑 -

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

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