【问题标题】:How do I implement this mongodb query & update operation (CSharp driver)?如何实现这个 mongodb 查询和更新操作(CSharp 驱动程序)?
【发布时间】:2014-02-03 07:18:34
【问题描述】:

我有这个收藏:

Books
[
{
  title: Book1,
  References: [ObjectId(1), ObjectId(3), ObjectId(5)] <- These are object ids of another collection
  Main-Reference: ObjectId(5)
},
{
  title: Book2,
  References: [ObjectId(2), ObjectId(5), ObjectId(7)] 
  Main-Reference: ObjectId(5)
}
{
  title: Book3,
  References: [ObjectId(5), ObjectId(7), ObjectId(9)] 
  Main-Reference: ObjectId(7)
},
]

我有一个操作,我从图书收藏中删除参考 示例:假设我必须从我的集合中删除 Reference ObjectId(5) 所以我的新收藏变成了这样:

Books
[
{
  title: Book1,
  References: [ObjectId(1), ObjectId(3)] <- ObjectId(5) is pulled
  Main-Reference: ObjectId(1) <- ObjectId(1) is new value as ObjectId(5) is deleted
},
{
  title: Book2,
  References: [ObjectId(2), ObjectId(7)]  <- ObjectId(5) is pulled
  Main-Reference: ObjectId(2) <- ObjectId(2) is now main reference
}
{
  title: Book3,
  References: [ObjectId(7), ObjectId(9)] <- ObjectId(5) is pulled
  Main-Reference: ObjectId(7) <- no changes here as ObjectId(7) still exists in References
},
]

目前我是这样做的:

第 1 步:从 References[] 具有 ObjectId(5) 的所有书籍中提取 ObjectId(5)

第 2 步:查询 Books 集合,其中 Main-Reference=ObjectId(5) 并使用 References: {$slice:1} 切片从 References 数组中获取第一个数组元素

第 3 步:更新第 2 步中找到的所有书籍并将 Main-Reference 替换为我从 slice 获得的第一个数组元素

这对我来说似乎很笨拙,并试图看看是否有更好的方法来做到这一点。

【问题讨论】:

    标签: mongodb mongodb-.net-driver


    【解决方案1】:

    如果我基本上明白你的意思,你基本上想要

    1. 从您的引用数组中拉出不需要的项目
    2. 将主引用字段的值设置为更改后数组的第一个元素

    并在一次更新中完成所有操作,而无需跨网络移动文档。

    但遗憾的是,这无法做到。这样做的主要问题是无法引用正在更新的文档中另一个字段的值。即便如此,要在不迭代的情况下执行此操作,您还需要访问 changed 数组以获取新的第一个元素。

    也许一种方法是重新考虑您的架构以完成您想要的。我在这里的选择会稍微扩展您的参考文档并消除对主要参考字段的需求。

    似乎您愿意接受更新的假设是,如果删除的引用是主引用,那么您可以将新的主引用设置为数组中的第一个元素。考虑到这一点,考虑以下结构:

    refs: [ { oid: "object1" }, { oid: "object2" }, { oid: "object5", main: true } ]
    

    通过将这些更改为具有oid 属性的文档,该属性将设置为 ObjectId,它提供了在文档上具有指定默认值的附加属性的选项。这可以很容易地查询确定哪个 Id 是主要参考。

    现在还要考虑如果从数组中拉出与 oid 字段中的“object5”匹配的文档会发生什么:

    refs: [ { oid: "object1" }, { oid: "object2" } ]
    

    因此,当您按照前面的逻辑查询哪个是main-reference 时,您接受数组中的第一个文档。当然,现在根据您的应用程序要求,如果您想设置不同的main-reference,您只需更改文档

    refs: [ { oid: "object1" }, { oid: "object2", main: true } ]
    

    现在的逻辑仍然是选择具有 main 属性为 true 的数组元素将优先出现,并且如上所示,如果该属性在任何元素文档上不存在,则回退到第一个元素。

    了解所有这些后,您在所有文档中从该数组中提取对一个对象的所有引用的操作变得非常简单,就像在 shell 中所做的那样(相同的格式基本上应该适用于任何驱动程序):

    db.books.update(
       { "refs.oid": "object5" },
       { $pull: { refs: {oid: "object5"} } }, false, true )
    

    查询和更新操作的两个额外参数分别是upsertmulti。在这种情况下,upsert 没有多大意义,因为我们只想修改存在的文档,而multi 意味着我们想要更新所有匹配的内容。默认设置是仅更改第一个文档。

    当然,我缩短了所有符号,但当然,根据您的意图,这些值可以是实际的 ObjectId。假设您对main-reference 的主要用途是在您检索到文档后,这似乎也是合理的。通过遵循概述的逻辑定义返回main-reference 的查询应该是可能的,但就目前而言,我在这里输入了很多内容,需要休息一下吃晚饭:)

    我认为这提供了一个值得重新考虑您的架构的案例,以避免为您想要实现的目标进行在线迭代。

    【讨论】:

    • 仅供参考。我开始了一个关于如何查询伪主引用 [这里}(stackoverflow.com/questions/21525882/…) 的问题,它有一些有趣的活动。我很确定那里的所有内容都已经适用于作为可接受的解决方案来增强我的建议。
    • 感谢您的回复。无法扩展 References 数组。
    • 可惜了。就目前而言,如果不迭代所有要更改的项目,您将无法实现所需的更新。移动哪个项目的指示器是项目内部的主要参考是我能看到的唯一避免这种情况的方法。如果架构不是您的决定,那么可能值得尝试说服负责人。
    猜你喜欢
    • 1970-01-01
    • 2012-03-04
    • 1970-01-01
    • 2012-11-02
    • 1970-01-01
    • 1970-01-01
    • 2022-09-29
    • 1970-01-01
    • 2011-12-17
    相关资源
    最近更新 更多