我是mongodb的新手并且正在使用它来存储嵌套文档。例如。每个文档包含每个班级的学生数组。我正在尝试更新每个阵列节点中的信息。有没有更好的方法来做,而不是一次更新每个数组元素?
这是我在集合中的记录 -
{
“_id” : “23343” ,
“class” : “Physics”,
“students”: [
{ “id” : “2412” , “name” : "Alice", “mentor” : 0 },
{ “id” : “2413” , “name” : "Bob, “mentor” : 0 },
]
}
集合中有多个这样的记录。
我有一份我需要为每条记录更新的课程列表。例如,我得到一组学生,以便上述记录更新如下 -
{
“_id” : “23343” ,
“class” : “Physics”,
“students”: [
{ “id” : “2412” , “name” : "Alice", “mentor” : "Mark" },
{ “id” : “2413” , “name” : "Bob, “mentor” : "Jackson" },
]
}
更新记录的最佳方法是什么?
我正在使用python。直观地说,我可以在课程的集合上做一个find()。我得到了一个光标。我可以在游标中为每个做一个。我相信mongodb会在update()上更新整个文档。
for record in courseCollection.find():
recordId = record['_id']
updatedList = getUpdatedStudentList( record['students'])
updatedRecord = prepareUpdatedRecord(updatedList)
courseCollection.update( {'_id' : recordId}, updateList)
pymongo文档站点没有讨论更新功能中的set选项。除非我使用它,我相信mongodb会更新整个文档。
通过传入_id来调用带有查询选项的更新似乎是不必要的,因为我只是执行了查询并拥有记录句柄。我可以通过不再对更新进行查询来以某种方式使用游标进行更新吗?
答案 0 :(得分:1)
您可以在更新中使用the $ operator和$ elemMatch。让我们从插入您的文档开始:
collection.insert({
"_id": "23343",
"class": "Physics",
"students": [
{"id": "2412", "name": "Alice", "mentor": 0},
{"id": "2413", "name": "Bob", "mentor": 0}]})
现在我将运行两个更新语句,首先添加导师“Mark”,然后是“Jackson”:
collection.update(
# Query portion.
{"_id": "23343", "students": {"$elemMatch": {"id": "2412"}}},
# Update portion; $ is the position of the matching student.
{"$set": {"students.$.mentor": "Mark"}})
collection.update(
# Query portion.
{"_id": "23343", "students": {"$elemMatch": {"id": "2413"}}},
{"$set": {"students.$.mentor": "Jackson"}})
每个更新语句仅影响“students”数组中一个子文档的“mentor”字段。
答案 1 :(得分:0)
我不确定问题到底是什么。简而言之:是的,您必须更新“父”对象,是的,您可以使用$set
或替换整个文档,这将是默认行为。差异主要是锁定,并发和所有权问题,这有点复杂。以下是您关注的一些问题:
使用游标更新嵌套的mongodb集合
请注意,没有“嵌套集合”,只有嵌入式文档。这很重要,因为mongodb的一等公民总是真正的文件本身。例如,find()
将返回文档,而不是单独的嵌入文档的子集。你可以做投影,但这只是一个输出转换,可以这么说。
我可以在课程的集合上做一个find()。我得到了一个光标。
你得到一个游标,但是因为你在主键上查询只能有一个匹配(主键是唯一的),即你可以使用findOne()
而你不需要迭代单一结果。
E.g。每个文档都包含每个班级的学生数组。
这些通常应该是引用给学生,即应该有一个单独的学生集合,因为你不想失去学生,因为它暂时没有被分配到任何课程。
pymongo文档站点没有讨论更新功能中的set选项。除非我使用它,我相信mongodb会更新整个文档。
这是真的。您可以在文档的$set
数组上执行students
。这可以避免覆盖任何其他字段,例如class
。另一方面,如果其他人在您使用编辑学生时更改了class
,那么更新是否仍然有意义?不明确的所有权是我对嵌入式文档的首要关注。
通过传入_id来调用带有查询选项的更新似乎没必要,因为我只是执行了查询并拥有记录句柄
...但究竟是记录的句柄?句柄是不可变的,唯一且通常很短的标识符。就像身份证。 _id
是句柄。我不知道python,但我想你可以编写一个方法来获取指向数据库对象的指针并执行更新,因为知道每个数据库对象都必须有一个名为_id
的字段。但是从数据库的角度来看,代码中的指针不是句柄,而是id。