使用mongo位置运算符($)并在多个数组中查找

时间:2016-01-04 18:53:33

标签: mongodb mongoose

让我将示例from the docs扩展为:

{
  _id: 4,
  tags: ['good', 'great', 'nice'], 
  grades: [
     { grade: 80, mean: 75, std: 8 },
     { grade: 85, mean: 90, std: 5 },
     { grade: 90, mean: 85, std: 3 }
  ]
}

现在,我想更新所有grade=85,其中还有good标记。我会尝试使用:

db.students.update(
   { tags: "good", "grades.grade": 85 },
   { $set: { "grades.$.std" : 6 } }
)

但是,mongo会将$设置为0,因为标记good是标记列表中的第一个。这会导致数据更改为:

{
  _id: 4,
  tags: ['good', 'great', 'nice'], 
  grades: [
     { grade: 80, mean: 75, std: 6 }, //←wrong
     { grade: 85, mean: 90, std: 5 },
     { grade: 90, mean: 85, std: 3 }
  ]
}

问题:有没有办法告诉mongo和/或猫鼬使用成绩中的职位来参考成绩?

2 个答案:

答案 0 :(得分:4)

之所以发生这种情况是因为您在单个查询文档中使用了两个数组。但不幸的是,MongoDB不支持它。

MongoDB documentation

  

查询文档应该只包含数组上的单个条件   正在投射的领域。多个条件可能会互相覆盖   内部并导致未定义的行为。

     

根据这些要求,以下查询不正确:

db.collection.find( { <array>: <value>, <someOtherArray>: <value2> },
                  { "<array>.$": 1 } )

您可以尝试编写类似的内容:

db.test.find({tags: "good", "grades.grade": 85 }).forEach(function(doc){ db.test.update(
{_id: doc._id, "grades.grade": 85 },
{ $set: { "grades.$.std" : 88 }}, 
{multi: true})})

答案 1 :(得分:0)

使用mongoose,您应该创建两个单独的模型。一个用于Students,另一个用于Grades。然后,让Students包含对Grades的引用。

这样可以轻松更新单个Grades

类似的东西:

var studentSchema = mongoose.Schema({
    tags: [String],
    grades: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Grade'
    }
});

var Student = mongoose.model('Student', studentSchema);

var gradeSchema = mongoose.Schema({
    grade: Number,
    mean: Number,
    std: Number
});

var Grade = mongoose.model('Grade', studentSchema);

您的更新代码可能如下所示:

Student.find({tags: { $in: ['good'] }}).populate('grades', { grade: 85 }).exec(function(err, students) {
    students.grades.forEach(function(grade) {
        grade.update(null, { std: 6 }, function(err, numAffected) {

        });
    });
});