简体   繁体   English

使用 MongoDB 中的嵌入式文档

[英]Working with embedded documents in MongoDB

I have a document with the following structure, some fields omitted for brevity;我有一个具有以下结构的文档,为简洁起见省略了一些字段;

{
  _id: 1,
  projectName: name,
  managers: [
    { managerId: manager1, status: false, startDate: startDate, endDate: endDate },
    { managerId: manager2, status: false, startDate: startDate, endDate: endDate }
    { managerId: manager3, status: true, startDate: startDate, endDate: endDate }
  ]
}

Here are my business rules;这是我的业务规则;

  • A project can be created with/without being assigned a manager可以在分配/不分配经理的情况下创建项目
  • A manager can be assigned/re-assigned a project - projects are transferable between managers可以为经理分配/重新分配项目 - 项目可以在经理之间转移
  • Each project should have a footprint of the managers involved每个项目都应该有所涉及的经理的足迹
  • A project cannot have more than one managers at the same time一个项目不能同时有多个经理

My intention is;我的意图是;

  • Upon re-assigning an officer, set the current active manager's status to false then push a new manager into the embedded document using a single query because it makes the most sense making a single round trip to the database unlike two round trips.在重新分配官员时,将当前活动经理的状态设置为 false,然后使用单个查询将新经理推送到嵌入文档中,因为与两次往返不同,对数据库进行一次往返最有意义。 The following is a snippet of what I came up with;以下是我想出的片段;

     Collection.update( { _id: 1, "managers.status": true }, { $set: { "managers.$.status": false }, $push: { managers: { managerId: newManagerId, status: true, startDate: startDate, endDate: endDate } } } );

Challenges挑战

My intention becomes a challenge because of the following circumstances;由于以下情况,我的意图成为挑战;

  • When a new project is created without a manager, the managers field which contains the embedded managers documents is not set在没有经理的情况下创建新项目时,未设置包含嵌入式经理文档的经理字段

  • How do I check whether an embedded document with the status of true exists so that I can set it to false and also if it doesn't push a new document in如何检查状态为 true 的嵌入文档是否存在,以便我可以将其设置为 false 以及它是否不推送新文档

Any ideas?有任何想法吗?

UPDATE更新

With reference to @Matt K's response, it made sense to make some better design decisions on my schema and made use of unshift instead of push.参考@Matt K 的回应,对我的架构做出一些更好的设计决策并使用 unshift 而不是 push 是有意义的。 I'm also setting the officers field default to an empty array on insert incase no manager is assigned yet.我还在插入时将官员字段默认设置为空数组,以防尚未分配经理。 Following is how my schema looks like after restructuring it;以下是我的架构重组后的样子;

    {
      _id: 1,
      projectName: name,
      managers: [
        { managerId: manager1, startDate: startDate },
        { managerId: manager2, startDate: startDate }
        { managerId: manager3, startDate: startDate }
      ]
    }

And here's my query;这是我的查询;

    Collection.update(
      { _id: 1 },
      {
        $push: {
           managers: {
              $each: [{ managerId: newManagerId, startDate: startDate }],
              $position: 0
           }
         }
       }
    );

Note that Mongo API doesn't provide unshift as an atomic operation but there's $position which achieves the same effect.请注意,Mongo API 没有提供 unshift 作为原子操作,但$position可以实现相同的效果。 So I no longer need status because all current managers will be at position 0 of the array.所以我不再需要状态,因为所有当前的经理都将位于数组的位置 0。 Also I don't need endDate because I can easily get that from a previous manager's document.此外,我不需要 endDate,因为我可以轻松地从前任经理的文档中获得它。 Hope this helps someone :)希望这对某人有所帮助:)

In keeping with your current schema (not recommended):与您当前的架构保持一致(不推荐):

First, save the entire document to the client:首先,将整个文档保存到客户端:

doc = {
  _id: 1,
  projectName: name,
  managers: [
    { managerId: "manager1", status: false, startDate: "startDate", endDate: "endDate" },
    { managerId: "manager2", status: false, startDate: "startDate",endDate: "endDate" },
    { managerId: "manager3", status: true, startDate: "startDate", endDate: "endDate" }
  ]
}

Add a managers field if it doesn't exist:如果不存在,则添加一个 manager 字段:

doc.managers = doc.managers || [];

Then, iterate over each field, setting status to false:然后,遍历每个字段,将 status 设置为 false:

for (var i = 0; i < doc.managers.length; i++) {
  doc.managers[i].status = false;
}

Push the new manager:推新经理:

doc.managers.push({
  managerId: "newManagerId", status: true, startDate: "startDate", endDate: "endDate"
})

Update the doc with your new one:用你的新文档更新文档:

Collection.update(1, doc)

OR, if you're really, really concerned with sending over a couple extra bytes:或者,如果您真的非常关心发送几个额外的字节:

Collection.update(1, {$set: {managers: doc.managers}})

After all that, I recommend you for ditch the status field in your managers array & create a new field called currentManager .毕竟,我建议您currentManager manager 数组中的 status 字段并创建一个名为currentManager的新字段。 Doing so does a few things:这样做有几件事:

  • it eliminates the effort you have to put in to keep the status fields mutually exclusive它消除了您为保持状态字段互斥而付出的努力

  • it makes finding the current manager VERY easy (no $elemMatch )它使找到现任经理非常容易(没有$elemMatch

  • it makes more sense, since your PK of the managers subdoc isn't the manager, rather a joint key of managerId, startDate, and endDate.这更有意义,因为您的经理子文档的 PK 不是经理,而是 managerId、startDate 和 endDate 的联合密钥。

Alternatively, get rid of the status field & unshift new managers instead of pushing.或者,摆脱状态字段并取消转移新经理而不是推动。 Then, you know field 0 always has the current (if one exists).然后,您知道字段 0 始终具有当前值(如果存在)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM