Javascript 在MongoDB中使用嵌入式文档

Javascript 在MongoDB中使用嵌入式文档,javascript,mongodb,meteor,Javascript,Mongodb,Meteor,我有一个具有以下结构的文档,为了简洁起见省略了一些字段 { _id: 1, projectName: name, managers: [ { managerId: manager1, status: false, startDate: startDate, endDate: endDate }, { managerId: manager2, status: false, startDate: startDate, endDate: endDate } { ma

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

{
  _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。我还在insert中将officers字段的默认值设置为空数组,以防尚未分配经理。下面是我的模式重组后的样子

    {
      _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,因为我可以很容易地从以前的经理的文档中获得它。希望这对某人有所帮助:)

符合您当前的模式(不推荐):

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

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;
}
使用新文档更新文档:

Collection.update(1, doc)
或者,如果您真的非常关心发送几个额外的字节:

Collection.update(1, {$set: {managers: doc.managers}})
在所有这些之后,我建议您放弃管理器数组中的status字段,创建一个名为
currentManager
的新字段。这样做可以做几件事:

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

  • 这使得查找当前管理器非常容易(无
    $elemMatch

  • 这更有意义,因为managers子文档的主键不是manager,而是managerId、startDate和endDate的联合键


或者,去掉status字段&取消新经理的职位,而不是推。然后,您知道字段0始终具有当前值(如果存在)。

当然是两次更新。使用
“managers.0”:{“$exists”:false}
作为其他更新的“空数组”测试条件。如果该语句没有更新,则执行另一个更新。
Collection.update(1, {$set: {managers: doc.managers}})