将对象推送到现有集合后,检索该对象的自生成_id值

时间:2014-07-09 01:02:02

标签: javascript node.js mongodb mongoose

我有一个mongodb文档,假设有模式

class: String,
class_teacher: String,
students: [
    { 
       student: String,
       marks: number
    }
]

在上面的例子中,如果我将一个新学生推送到该集合,它将为每个学生生成一个_id,我通过使用整个文档的更新查询来完成它。

  1. 这是正确的方法吗?

  2. 如果是,我如何在推送学生对象后立即获得每个学生的_id?

  3. 过了一段时间,如果我想更新单个学生的分数,最好的方法是什么?

1 个答案:

答案 0 :(得分:2)

在不错的模式下,我会回答所有你的问题",这里有一些演示代码:

var mongoose = require("mongoose"),
    Schema = mongoose.Schema;


mongoose.connect('mongodb://localhost/test');

var classSchema = new Schema({
  class: String,
  teacher: String,
  students: [{ student: String, marks: Number }]
});

var Class = mongoose.model("Class", classSchema);

var myclass = new Class();

myclass.students.push(
  { student: "bill", marks: 10 },
  { student: "ted", marks: 5 }
);

console.log("Whole:\n %s\n",myclass);
console.log("Last added _id: %s\n",myclass.students.slice(-1)[0]._id);

myclass.save(function(err,myclass) {
  if (err) throw err;

  Class.findOneAndUpdate(
    { "students.student": "ted" },
    { "$set": { "students.$.marks": 7 } },
    function(err,doc) {
      if (err) throw err;

      console.log(doc);
    }
  );

});

总的来说:

  1. 确定没问题,即使您可能会发现为#34; Student"定义您的架构。从长远来看,单独来说可以更容易维护:

    var studenSchema = new Schema({
        student: String,
        marks: Number
    });
    
    var classSchema = new Schema({
        class: String,
        teacher: String,
        students: [studentSchema]
    });
    
  2. 当您修改此方式时,数组中最后添加的元素可以通过.slice()拉出,然后您可以获得最后_id值。

    console.log("Last added _id: %s\n",myclass.students.slice(-1)[0]._id);
    
  3. 使用.findOneAndUpdate()或类似操作最好更新标记。在这里,您查询匹配文档和数组元素,并使用positional $运算符更新正确的元素:

    Class.findOneAndUpdate(
      { "students.student": "ted" },
      { "$set": { "students.$.marks": 7 } },
      function(err,doc) {
        if (err) throw err;
    
        console.log(doc);
      }
    );
    
  4. 这也会返回已修改的文档,以便您可以查看更改。对于"批量"您将使用.update()方法以及" multi"选项。

    你也可以"添加"使用$push运算符将新学生添加到数组中,就像使用显示的方法返回文档之前一样,这样您也可以通过这种方式应用获取新的_id值:

      Class.findOneAndUpdate(
        { "students.student": "ted" },
        { "$push": { "students": { "student": "sally", "marks": 4 }} },
        function(err,doc) {
          if (err) throw err;
    
          console.log("Whole:\n %s", doc);
          console.log("Last added _id: %s\n",doc.students.slice(-1)[0]._id);
        }
      );
    

    这会产生如下结果:

    Whole:
    { _id: 53bc9844c1cbd4d24eac8db6,
      __v: 0,
      students:
       [ { student: 'bill', marks: 10, _id: 53bc9844c1cbd4d24eac8db7 },
         { student: 'ted', marks: 7, _id: 53bc9844c1cbd4d24eac8db8 },
         { student: 'sally', marks: 4, _id: 53bca6c346d93b32624e5af4 } ] }
    
    Last added id: 53bca6c346d93b32624e5af4
    

    如果您需要其他模式验证功能或字段值的其他挂钩,则需要单独.find()个文档,在代码中修改,然后.save()。但这些是替代方法,通常会创造更少的线路流量#34;而不是处理整个文件。