MongoDB Double Upsert和Push

时间:2015-05-18 21:00:46

标签: javascript mongodb meteor mongodb-query

我在Mongo中有以下数据结构:

{
  "_id": "L7ucxMsTSfTDtctnt",
  "lectures": [
    {
      "_id": "Tfr3DMxavZwP5yy6F",
      "notes": [
        {
          "slide": 1,
          "notes": "First Note",
          "timestamp": "2015-05-18T20:18:36.510Z"
        },
        {
          "slide": 2,
          "notes": "Another note",
          "timestamp": "2015-05-18T20:18:36.510Z"
        }
      ]
    }
  ]
}

我正在尝试进行三次upsert和数组推送。因此,如果外部_id不存在,请创建它,否则更新它。如果讲座_id不存在,请创建它,否则更新它。如果notes _id不存在,则创建对象并推送到notes数组,否则更新它。

是否有可能做一些复杂的事情?我可以分三个步骤完成,但我经常调用这个函数,并担心性能。

1 个答案:

答案 0 :(得分:2)

如果你能分三个步骤完成,那就非常令人印象深刻......哎呀,只是试图编写一个查询来返回一个带有该模式的单个注释对象,这会伤害我的大脑。 (尝试一下,你不会喜欢它)。

第二层之后,mongo中的对象模式数组开始变得非常麻烦。通常最好使用新的集合或将其存储为子文件(doc.lectures['alsfjljfldjf5084534']),因为这样你就可以引用一个内存地址,而不是试图执行一个嵌套的$elemmatch

无论如何,要回答你的问题,它只是1次upsert,因为它只有1个doc。当你想到整个事情是1 doc时,你会更容易理解。只需获取文档&将其保存为JS对象。修改对象&然后整个事情。不要担心转移几个额外字节的重复数据。使用疯狂的迭代查询来困扰您的数据库以查找您要编辑的文档中的特定点是waaaaaayyyy更多的负担。

在这种特殊情况下,你已经正确建模了ER(1个课程有很多讲座,1个讲座有很多笔记)但是,根据你的查询模式,你可能想把课程放在他们自己的集合中。在课堂集合中将classID包含为FK。然后,可以选择创建notes子目录以便于访问。

这样做,获取注释对象就像这样简单: Lectures.findOne({notesID: '234asfj'})。当然,你失去了原子性,但这是一个很小的代价。

编辑:

doc = {}; //empty object
subDocId = Random.id(); //ref for subdoc
doc[subDocId] = {
    notes: 1,
    text: 'foo'
}; // create subdoc
Lecture.insert(doc); //insert subdoc

var doc = Lectures.findOne(); //get it
doc["Tfr3DMxavZwP5yy6F"] = {foo:1, bar:2} //mod it
Lecture.insert(doc); //upload it