Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/465.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript $pull对象来自数组,以及$pull引用来自另一个数组_Javascript_Node.js_Mongodb_Mongodb Query - Fatal编程技术网

Javascript $pull对象来自数组,以及$pull引用来自另一个数组

Javascript $pull对象来自数组,以及$pull引用来自另一个数组,javascript,node.js,mongodb,mongodb-query,Javascript,Node.js,Mongodb,Mongodb Query,请从客户机集合中考虑此文档: client: { services: [ { _id: 111, someField: 'someVal' }, { _id: 222, someField: 'someVal' } ... // More services ] staff: [ { _id: 'aaa', someField: 'someVal', s

请从客户机集合中考虑此文档:

client: {
  services: [
    {
      _id: 111,
      someField: 'someVal'
    },
    {
      _id: 222,
      someField: 'someVal'
    }
    ... // More services
  ]

  staff: [
    {
      _id: 'aaa',
      someField: 'someVal',
      servicesProvided: [111, 222, 333, ...]
    },
    {
      _id: 'bbb',
      someField: 'someVal',
      servicesProvided: [111, 555, 666, ...]
    },
    {
      _id: 'ccc',
      someField: 'someVal',
      servicesProvided: [111, 888, 999, ...]
    }
    ... // More staff
  ]
}
一个客户可以有许多员工。每位员工都有他或她提供的服务的参考资料。如果删除了某项服务,则还需要删除所有员工中对该服务的引用

我想从
服务
中删除(拉取)一个对象(服务),并在同一查询中删除所有
员工
对象中提供的
服务
中可能的引用`

例如,如果我使用
\u id
111删除服务,我还希望删除提供此服务的staffmembers中对此服务的所有引用


如何编写此查询

这就是事情变得有点糟糕的地方。实际上,如何更新与单个文档中的条件相匹配的“多个”数组项

这里有一点来自操作员的背景信息:

嵌套数组 位置$operator不能用于遍历多个数组的查询,例如遍历嵌套在其他数组中的数组的查询,因为$placeholder的替换项是单个值

这说明了故事的“部分”,但这里针对这个问题的主要观点是“不止一个”

因此,即使“嵌套”部分由于需要执行的操作而没有显式地
true
,但重要的因素是“不止一个”。为了演示,让我们考虑一下:

{
  services: [
    {
      _id: 111,
      someField: 'someVal'
    },
    {
      _id: 222,
      someField: 'someVal'
    }
  ],

  staff: [
    {
      _id: 'aaa',
      someField: 'someVal',
      servicesProvided: [111, 222, 333, ...]
    },
    {
      _id: 'bbb',
      someField: 'someVal',
      servicesProvided: [111, 555, 666, ...]
    },
    {
      _id: 'ccc',
      someField: 'someVal',
      servicesProvided: [111, 888, 999, ...]
    }
  ]
}
现在,您要求删除
111
值。这始终是示例中提供的“第一个”值。因此,我们可以假设情况是这样的,那么更新是“看起来很简单:

 db.collection.update(
     { 
         "_id": ObjectId("542ea4991cf4ad425615b84f"),
     },
     { 
         "$pull": {
             "services": { "_id": 111 },
             "staff.servicesProvided": 111
         }
     }
 )
但是。这不会达到您预期的效果,因为元素不会像您预期的那样从所有“staff”数组元素中提取。事实上,它们中没有一个。唯一有效的方法是:

 db.collection.update(
     { 
         "_id": ObjectId("542ea4991cf4ad425615b84f"),
         "staff.servicesProvided": 111
     },
     { 
         "$pull": {
             "services": { "_id": 111 },
             "staff.$.servicesProvided": 111
         }
     }
 )
但是你猜怎么着!实际上只有“第一个”数组元素被更新了。所以当你看上面的语句时,它基本上是这样说的

再次,假设我们只是在一个现代MongoDB shell中使用MongoDB 2.6版或更高版本的服务器进行测试。那么我们得到的响应如下:

WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
请稍等。上一条语句刚刚告诉我们有多少文档被“修改”。因此,尽管我们一次只能更改数组的一个元素,但这里有一些重要的条件反馈

从“Bulk Operations API”操作中获得的新“WriteResult”对象的真正伟大之处在于,它实际上是在shell中完成的,它告诉您是否有东西被上一条语句“修改”了。这比“遗留”要好得多“写下回应,这为我们在循环考虑方面做出一些重要决策提供了基础。例如“我们上次的操作是否确实‘修改’了文档,然后我们是否应该继续?”

因此,这是一个重要的“流控制”点,即使通用MongoDB API本身不能一次“更新所有元素”。现在有一个可测试的案例来决定在循环中“继续”到哪里。这就是我最后所说的“结合”你已经学到的东西的意思。因此,最终我们可以得出如下清单:

var bulk = db.collection.initializeOrderedBulkOp();
var modified = 1;

async.whilst(
    function() { return modified },
    function(callback) {
        bulk.find(
            { 
                "_id": ObjectId("542ea4991cf4ad425615b84f"),
                "staff.servicesProvided": 111
            }
        ).updateOne(
            { 
                "$pull": {
                     "services": { "_id": 111 },
                     "staff.$.servicesProvided": 111
                }
            }
        );

        bulk.execute(function(err,result) {
            modified = result.nModfified();
            callback(err);
        });
    },
    function(err) {
      // did I throw something! Suppose I should so something about it!
    }
);
{
  "services": [
    {
      "_id": 111,
      "someField": "someVal"
    },
    {
      "_id": 222,
      "someField": "someVal"
    }
  ],

  "provided": [ 
      { "_id": "aaa", "service": 111 },
      { "_id": "aaa", "service": 222 },
      { "_id": "aaa", "service": 111 }
  ]
}
db.collection.update(
    {  "_id": ObjectId("542ea4991cf4ad425615b84f") },
    {
        "$pull": {
            "services": { "_id": 111 },
            "provided": { "_id": 111 }
        }
    }
);
或者基本上是那种可爱的东西。因此,您需要从“批量操作”
.execute()
中获得的“result”对象来告诉您是否修改了某些内容。在它仍然存在的地方,然后在这里再次“重新迭代”循环,执行相同的更新并再次请求结果

最终,更新操作将告诉您“什么都没有”被修改过。这是当您退出循环并继续正常操作时

现在,处理此问题的另一种方法可能是读入整个对象,然后进行所需的所有修改:

db.collection.findOne(
    { 
        "_id": ObjectId("542ea4991cf4ad425615b84f"),
        "staff.servicesProvided": 111
    },
    function(err,doc) {
        doc.services = doc.services.filter(function(item) {
            return item._id != 111;
        });

        doc.staff = doc.staff.filter(function(item) {
            item.serviceProvided = item.servicesProvided.filter(function(sub) {
                return sub != 111;
            });
            return item;
        });
       db.collection.save( doc );
    }
);
有点过分了。不完全是原子的,但足够接近测量

因此,您不可能在单个写入操作中真正做到这一点,至少不需要处理“读取”文档,然后在修改内容后“写入”整个内容。但是你可以采取“迭代”的方法,有一些工具可以让你控制它

另一种可能的方法是改变建模方式,如下所示:

var bulk = db.collection.initializeOrderedBulkOp();
var modified = 1;

async.whilst(
    function() { return modified },
    function(callback) {
        bulk.find(
            { 
                "_id": ObjectId("542ea4991cf4ad425615b84f"),
                "staff.servicesProvided": 111
            }
        ).updateOne(
            { 
                "$pull": {
                     "services": { "_id": 111 },
                     "staff.$.servicesProvided": 111
                }
            }
        );

        bulk.execute(function(err,result) {
            modified = result.nModfified();
            callback(err);
        });
    },
    function(err) {
      // did I throw something! Suppose I should so something about it!
    }
);
{
  "services": [
    {
      "_id": 111,
      "someField": "someVal"
    },
    {
      "_id": 222,
      "someField": "someVal"
    }
  ],

  "provided": [ 
      { "_id": "aaa", "service": 111 },
      { "_id": "aaa", "service": 222 },
      { "_id": "aaa", "service": 111 }
  ]
}
db.collection.update(
    {  "_id": ObjectId("542ea4991cf4ad425615b84f") },
    {
        "$pull": {
            "services": { "_id": 111 },
            "provided": { "_id": 111 }
        }
    }
);
等等。因此,查询变成如下所示:

var bulk = db.collection.initializeOrderedBulkOp();
var modified = 1;

async.whilst(
    function() { return modified },
    function(callback) {
        bulk.find(
            { 
                "_id": ObjectId("542ea4991cf4ad425615b84f"),
                "staff.servicesProvided": 111
            }
        ).updateOne(
            { 
                "$pull": {
                     "services": { "_id": 111 },
                     "staff.$.servicesProvided": 111
                }
            }
        );

        bulk.execute(function(err,result) {
            modified = result.nModfified();
            callback(err);
        });
    },
    function(err) {
      // did I throw something! Suppose I should so something about it!
    }
);
{
  "services": [
    {
      "_id": 111,
      "someField": "someVal"
    },
    {
      "_id": 222,
      "someField": "someVal"
    }
  ],

  "provided": [ 
      { "_id": "aaa", "service": 111 },
      { "_id": "aaa", "service": 222 },
      { "_id": "aaa", "service": 111 }
  ]
}
db.collection.update(
    {  "_id": ObjectId("542ea4991cf4ad425615b84f") },
    {
        "$pull": {
            "services": { "_id": 111 },
            "provided": { "_id": 111 }
        }
    }
);
这确实是一个单一的更新操作,一次删除所有内容,因为每个元素都包含在单一数组中


所以有很多方法可以做到这一点,但建模方式实际上取决于应用程序数据访问模式。选择最适合您的解决方案。这就是您首先选择MongoDB的原因。

现在对您的其他链接发表了评论,但我想我理解您的意图。通过显示共享相同“服务”id值的“多个”“人员”条目可能更好地演示。但这就是你要问的,对吗?如何从“staff”数组的“多个”成员下的子数组中删除该条目。对吗?顺便说一句,如果我没记错的话,你在node.js和mongoskin上。是的!这就是我想要的=)。Nodejs和mongoskin正确!酷。是的,这是“可能的”,但不是在单个查询中。我想是时候把前面问题的一些部分放在一起了:)如果这是一个复杂的操作,我应该把它看作是数据结构不好的标志吗?本周早些时候,我将员工和服务分为不同的集合,通过参考链接到一个客户。我后来将它们嵌入到客户机中,因为我推断它们总是在特定客户机的上下文中被“看到”,并且它们可能也不会变得很大。我刚刚意识到,如果我要在多个查询中执行此操作,这一点都不难!步骤1:从DB获取客户机,并仅投影staff数组。步骤2:删除内存中json对象上给定服务id的所有实例。步