在MongoDB中使用嵌入式文档

时间:2015-06-18 13:06:55

标签: javascript mongodb meteor

我有一个具有以下结构的文档,为简洁起见省略了一些字段;

{
  _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 }
  ]
}

以下是我的业务规则;

  • 可以创建项目,无需分配经理
  • 可以为经理分配/重新分配项目 - 项目可以在经理之间转移
  • 每个项目都应该包含相关管理人员的足迹
  • 项目不能同时拥有多个经理

我的意图是;

  • 重新分配人员后,将当前活动管理员的状态设置为false,然后使用单个查询将新管理员推送到嵌入式文档中,因为最有意义的是单次往返数据库与两次往返不同。 以下是我提出的内容摘要;

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

挑战

由于以下情况,我的意图成为挑战;

  • 在没有经理的情况下创建新项目时,未设置包含嵌入式经理文档的经理字段

  • 如何检查状态为true的嵌入式文档是否存在,以便我可以将其设置为false,如果它没有在

  • 中推送新文档

有什么想法吗?

更新

参考@Matt K的回复,在我的架构上做出更好的设计决策并使用unshift而不是push是有意义的。我还在插入时将人员字段默认设置为空数组,但尚未分配管理员。以下是重构后我的架构的样子;

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

这是我的疑问;

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

注意 Mongo API并不提供原始操作的非移位功能,但是$position实现了相同的效果。因此,我不再需要状态,因为所有当前管理器都将位于阵列的第0位。此外,我不需要endDate,因为我可以轻松地从之前的经理文档中获取该日期。希望这有助于某人:)

1 个答案:

答案 0 :(得分:1)

与您当前的架构保持一致(不推荐):

首先,将整个文档保存到客户端:

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" }
  ]
}

如果不存在,请添加经理字段:

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

然后,迭代每个字段,将状态设置为false:

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

推新经理:

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

使用新文档更新文档:

Collection.update(1, doc)

或者,如果你真的非常关心发送几个额外的字节:

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

毕竟,我建议您在管理人员阵列中放弃状态字段。创建一个名为currentManager的新字段。这样做有以下几点:

  • 它消除了您必须付出的努力以保持状态字段互斥

  • 这使得找到当前的经理非常容易(没有$elemMatch

  • 它更有意义,因为管理器subdoc的PK不是管理器,而是managerId,startDate和endDate的联合键。

或者,摆脱状态字段&amp;不转移新经理而不是推动。然后,您知道字段0始终具有当前(如果存在)。

相关问题