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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4588303/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 11:54:36  来源:igfitidea点击:

In mongoDb, how do you remove an array element by its index?

mongodb

提问by dannie.f

In the following example, assume the document is in the db.peoplecollection.

在以下示例中,假设文档位于db.people集合中。

How to remove the 3rd element of the interestsarray by it's index?

如何通过索引删除兴趣数组的第三个元素?

{
  "_id" : ObjectId("4d1cb5de451600000000497a"),           
  "name" : "dannie",  
  "interests" : [  
    "guitar",  
    "programming",           
    "gadgets",  
    "reading"  
  ]   
}

This is my current solution:

这是我目前的解决方案:

var interests = db.people.findOne({"name":"dannie"}).interests;  
interests.splice(2,1)  
db.people.update({"name":"dannie"}, {"$set" : {"interests" : interests}});

Is there a more direct way?

有没有更直接的方法?

回答by Javier Ferrero

There is no straight way of pulling/removing by array index. In fact, this is an open issue http://jira.mongodb.org/browse/SERVER-1014, you may vote for it.

没有通过数组索引拉/删除的直接方法。事实上,这是一个开放的问题http://jira.mongodb.org/browse/SERVER-1014,你可以投票支持它。

The workaround is using $unset and then $pull:

解决方法是使用 $unset 然后使用 $pull:

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

Update: as mentioned in some of the comments this approach is not atomic and can cause some race conditions if other clients read and/or write between the two operations. If we need the operation to be atomic, we could:

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

  • Read the document from the database
  • Update the document and remove the item in the array
  • Replace the document in the database. To ensure the document has not changed since we read it, we can use the update if current pattern described in the mongo docs
  • 从数据库中读取文档
  • 更新文档并移除数组中的项目
  • 替换数据库中的文档。为确保文档自我们阅读后没有更改,我们可以使用更新,如果当前模式在 mongo 文档中描述

回答by Sunseeker

You can use $pullmodifier of updateoperation for removing a particular element in an array. In case you provided a query will look like this:

您可以使用操作$pull修饰符update来删除数组中的特定元素。如果您提供的查询将如下所示:

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

Also, you may consider using $pullAllfor removing all occurrences. More about this on the official documentation page - http://www.mongodb.org/display/DOCS/Updating#Updating-%24pull

此外,您可以考虑使用$pullAll用于删除所有出现。更多关于官方文档页面的信息 - http://www.mongodb.org/display/DOCS/Updating#Updating-%24pull

This doesn't use index as a criteria for removing an element, but still might help in cases similar to yours. IMO, using indexes for addressing elements inside an array is not very reliable since mongodb isn't consistent on an elements order as fas as I know.

这不使用索引作为删除元素的标准,但在与您类似的情况下仍然可能有所帮助。IMO,使用索引来寻址数组中的元素并不是很可靠,因为 mongodb 在元素顺序上与我所知的 fas 不一致。

回答by Stephen Orr

Rather than using the unset (as in the accepted answer), I solve this by setting the field to a unique value (i.e. not NULL) and then immediately pulling that value. A little safer from an asynch perspective. Here is the code:

我没有使用未设置(如已接受的答案),而是通过将字段设置为唯一值(即不是 NULL)然后立即提取该值来解决此问题。从异步的角度来看更安全一些。这是代码:

    var update = {};
    var key = "ToBePulled_"+ new Date().toString();
    update['feedback.'+index] = key;
    Venues.update(venueId, {$set: update});
    return Venues.update(venueId, {$pull: {feedback: key}});

Hopefully mongo will address this, perhaps by extending the $position modifier to support $pull as well as $push.

希望 mongo 能够解决这个问题,也许通过扩展 $position 修饰符来支持 $pull 和 $push。

回答by Climax

I would recommend using a GUID (I tend to use ObjectID) field, or an auto-incrementing field for each sub-document in the array.

我建议使用 GUID(我倾向于使用 ObjectID)字段,或为数组中的每个子文档使用自动递增字段。

With this GUID it is easy to issue a $pull and be sure that the correct one will be pulled. Same goes for other array operations.

使用此 GUID 很容易发出 $pull 并确保将拉取正确的。其他数组操作也是如此。

回答by Schwarz54

For people who are searching an answer using mongoose with nodejs. This is how I do it.

对于使用 mongoose 和 nodejs 搜索答案的人。我就是这样做的。

exports.deletePregunta = function (req, res) {
let codTest = req.params.tCodigo;
let indexPregunta = req.body.pregunta; // the index that come from frontend
let inPregunta = `tPreguntas.0.pregunta.${indexPregunta}`; // my field in my db
let inOpciones = `tPreguntas.0.opciones.${indexPregunta}`; // my other field in my db
let inTipo = `tPreguntas.0.tipo.${indexPregunta}`; // my  other field in my db

Test.findOneAndUpdate({ tCodigo: codTest },
    {
        '$unset': {
            [inPregunta]: 1, // put the field with [] 
            [inOpciones]: 1,
            [inTipo]: 1
        }
    }).then(()=>{ 
    Test.findOneAndUpdate({ tCodigo: codTest }, {
        '$pull': {
            'tPreguntas.0.pregunta': null,
            'tPreguntas.0.opciones': null,
            'tPreguntas.0.tipo': null
        }
    }).then(testModificado => {
        if (!testModificado) {
            res.status(404).send({ accion: 'deletePregunta', message: 'No se ha podido borrar esa pregunta ' });
        } else {
            res.status(200).send({ accion: 'deletePregunta', message: 'Pregunta borrada correctamente' });
        }
    })}).catch(err => { res.status(500).send({ accion: 'deletePregunta', message: 'error en la base de datos ' + err }); });
 }

I can rewrite this answer if it dont understand very well, but I think is okay.

如果不太明白,我可以重写这个答案,但我认为还可以。

Hope this help you, I lost a lot of time facing this issue.

希望这对你有帮助,我在这个问题上浪费了很多时间。

回答by Xavier Guihot

Starting in Mongo 4.4, the $functionaggregation operator allows applying a custom javascript function to implement behaviour not supported by the MongoDB Query Language.

从 开始Mongo 4.4$function聚合运算符允许应用自定义 javascript 函数来实现 MongoDB 查询语言不支持的行为。

For instance, in order to update an array by removing an element at a given index:

例如,为了通过删除给定索引处的元素来更新数组:

// { "name": "dannie", "interests": ["guitar", "programming", "gadgets", "reading"] }
db.collection.update(
  { "name": "dannie" },
  [{ $set:
    { "interests":
      { $function: {
          body: function(interests) { interests.splice(2, 1); return interests; },
          args: ["$interests"],
          lang: "js"
      }}
    }
  }]
)
// { "name": "dannie", "interests": ["guitar", "programming", "reading"] }

$functiontakes 3 parameters:

$function需要3个参数:

  • body, which is the function to apply, whose parameter is the array to modify. The function here simply consists in using splice to remove 1 element at index 2.
  • args, which contains the fields from the record that the bodyfunction takes as parameter. In our case "$interests".
  • lang, which is the language in which the bodyfunction is written. Only jsis currently available.
  • body,这是要应用的函数,其参数是要修改的数组。这里的功能只是使用 splice 删除索引 2 处的 1 个元素。
  • args,其中包含该body函数作为参数的记录字段。在我们的情况下"$interests"
  • lang,这body是编写函数的语言。仅js当前可用。

回答by Mohan Krishnan

Instead of using $pull we can use $pop for removing elements in an array by its index. But you should subtract 1 from index position for removing based on the index.

我们可以使用 $pop 代替使用 $pull 通过索引删除数组中的元素。但是您应该从索引位置减去 1 以根据索引删除。

For E.g if you want to remove the element in index 0 you should use -1, for index 1 you should use 0 and so on...

例如,如果你想删除索引 0 中的元素,你应该使用 -1,对于索引 1,你应该使用 0 等等......

Query To Remove 3rd Element(gadgets):

删除第三个元素(小工具)的查询:

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

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

for reference: https://docs.mongodb.com/manual/reference/operator/update/pop/

供参考:https: //docs.mongodb.com/manual/reference/operator/update/pop/