我有以下文件:
{
_id: 1
items: ['1a', '1b', '1c']
},
{
_id: 2,
items: ['2a', '2b', '2c']
}
是否可以从这些文件中提取项目,但仅限于所有项目都存在?
解释:
我需要从这些文档中提取“1a”,“1c”和“2b”elemnet,所以如果我发出如下查询:
var updateObj = ['1a', '1c', '2b'];
db.collection.update({_id : {$in updateObj}}, {$pullAll: {items: updateObj}});
比将返回成功并拉动物品。
但是,如果发出以下查询:
var updateObj = ['1a', '1c', '2z'];
db.collection.update({_id : {$in updateObj}}, {$pullAll: {items: updateObj}});
然后我希望更新失败,因为任何文档中都不存在2z。
答案 0 :(得分:0)
我真的不知道你如何获得第一个查询的好结果,因为你没有任何匹配'1a'或'1c'或'2b'的ID。
我认为您的查询应如下所示:
db.collection.update({items: {$in: updateObj}}, {$pullAll: {items: updateObj}}, {multi: true});
答案 1 :(得分:0)
好的,我花了一些时间来解决问题,但我相信我现在明白了。坚持下去,因为这是一个冗长的解释,我希望我不会把你与英语混淆。
正如你所说,鉴于$in你想要做的是$pullAll来自数组字段的元素,,只有 所有< / strong>找到的那些元素。 (您的问题可能已接受编辑,可能会在现在清除它。)
按照目前的情况,你会发现你的第二案例当然会从匹配的文档中拉出拉匹配元素('1a','1c')虽然你的'2z'元素与集合中的任何文档都不匹配。根据你想要达到的目标,我认为最后一句话是最重要的一点。
此条件的主要问题,以及它不起作用的原因,是因为您匹配的元素跨越不同的文档。
采取您希望匹配的第一个案例。指定的元素('1a','1c','2b')匹配您作为样本提供的两个文档。这是因为给定$in
运算符,两个文档都满足条件,其中 first 具有元素('1a','1c')和 second 匹配('2b')作为其中一个要素。
此处您的操作很简单(假设您使用multi
更新),其中匹配两个文档,并且更新部分很简单。因此,对于匹配的文档,我们只想从提供的列表中拉出数组元素。这很好用。
在第二个的情况下,我们可以看到“2z”不会在集合中的任何文档中看到。但是,由于我们跨越文档以及使用$in
,我们发现第一个文档与条件匹配('1a'和' 1c'存在并匹配$ in)。那么这意味着$pullAll
带有给出的参数将在此文档中行为。正如您将意识到的那样,$pullAll
并不关心所有元素是否存在,它只会提取与给定列表匹配的所有内容。
所以在这里你可以看到问题,我们是在多个文档上,一个文档(或更多)将符合这些条件,但你想做一些不同的事情。 / p>
您可以用update
表单执行此操作吗?好吧,不。但我们可以采取另一种方法。我们想要做的是测试所有元素匹配集合中的文档。因此,在我们做出更新决定之前,我们需要首先分析。
db.collection.aggregate([
// Look for "just what we are expecting to match"
{$match: {items: {$in: ['1a','1c', '2z']}} },
// Unwind the array for matching
{$unwind: "$items"},
// Pool this back into "one document"
{$group: { _id: null, items: {$addToSet: "$items"}}}
// Now ask the question again "Do you match **all**?"
{$match: {items: {$all: ['1a', '1c', '2z']}}}
])
那么这将做什么,(并通过逐步查看更好地解释)是查看可能匹配您的初始集并将分组的文档>元素一起作为所有文档中的实际集。然后我们终于提出问题,“ 所有在集合中找到的这些东西?”
上面的过程中元素中的'2z'不会返回结果,但是'2b'会返回结果。因此,通过测试执行之前发布更新语句,您可以获得所需的结果。
更新时不是失败,但您可以检查失败 之前您是否发布更新并满足您想要的条件
唷!那是我的一杯酒?