在mongoDb中,如何通过索引删除数组元素?

7 浏览
0 Comments

在mongoDb中,如何通过索引删除数组元素?

在下面的例子中,假设文档位于集合中。

如何根据索引删除数组的第三个元素?

{

"_id": ObjectId("4d1cb5de451600000000497a"),

"name": "dannie",

"interests": [

"guitar",

"programming",

"gadgets",

"reading"

]

}

这是我目前的解决方案:

var interests = db.people.findOne({"name":"dannie"}).interests;

interests.splice(2,1);

db.people.update({"name":"dannie"}, {"$set" : {"interests" : interests}});

是否有更直接的方法?

0
0 Comments

在MongoDB中,如何通过索引删除数组元素?

问题的出现原因是用户想要在MongoDB中通过索引删除数组元素,但是MongoDB对于元素的顺序不是很一致,所以使用索引来删除元素不是很可靠。

解决方法是使用$pull操作符来删除数组中的特定元素。具体操作如下:

db.people.update({"name":"dannie"}, {'$pull': {"interests": "guitar"}})

如果想要删除所有出现的元素,可以考虑使用$pullAll操作符。更多详情请参考官方文档:http://www.mongodb.org/display/DOCS/Updating#Updating-%24pull

虽然这种方法并没有使用索引作为删除元素的条件,但是在类似的情况下仍然有用。因为MongoDB对于元素的顺序不是一致的,所以使用索引来定位数组中的元素并不是很可靠。实际上,所有的文档都是有序的集合,但是很多驱动程序并没有按照这种方式处理它们。而且,如果一个文档在更新操作后需要移动(因为超过了填充因子的限制),那么键的顺序会突然变为字母顺序(在底层,我认为它们是按照它们的二进制值排序的,这个猜测是基于我的知识,数组实际上是具有连续整数键的标准文档)。

使用$pull操作符来删除元素可以避免使用unset+pull的问题,但是需要确保字典是严格有序的。大多数语言中的字典是无序的,所以可能需要一些额外的工作来实现这一点。

关于元素的一致性,我的期望用例是这样的:客户端从MongoDB请求JSON数据,然后如果客户端选择从JSON数组中删除一个项,它将传递数组的索引给服务器进行删除。如果数组项的位置发生变化,那将是奇怪的,但这可以解释为什么他们不能实现这个功能。

数组始终会保持它们的“顺序”,因为它们基本上是哈希表,其中键就是给定的索引。这就是JSON的工作原理,因为这就是JS的工作原理。例如,["zero", "one", "two"]类似于{"0":"zero", "1":"one", "2":"two"},而这些键会转换成数组的顺序。

0
0 Comments

在MongoDB中,没有直接按数组索引进行删除/移除的方法。实际上,这是一个未解决的问题,你可以在http://jira.mongodb.org/browse/SERVER-1014上为其投票。

解决方法是使用$unset和$pull:

db.lists.update({}, {$unset : {"interests.3" : 1 }})

db.lists.update({}, {$pull : {"interests" : null}})

更新:正如一些评论中提到的,这种方法是不原子的,如果在两个操作之间有其他客户端进行读取和/或写入,可能会导致一些竞争条件。如果我们需要操作是原子的,我们可以:

1. 从数据库中读取文档

2. 更新文档并删除数组中的项

3. 替换数据库中的文档。为了确保文档在我们读取它后没有发生变化,我们可以使用Mongo文档中描述的"update if current"模式。

已经过去了一年半了?Mongodb的情况还是这样吗?

下一个答案更直接,对我也起作用。虽然它不是按索引删除,而是按值删除。

- 如果在计算索引位置和执行$unset之间的时间内数据库发生了变化,这个解决方案会不会存在问题呢?

这个解决方案不是原子的,所以如果你的代码没有准备好处理数组中的null条目,很可能会导致一些隐晦的竞争条件。

已经过去了8年,这个问题仍然没有被实现...

0