2011-01-03 11 views
82
{ 

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

En el ejemplo anterior, supongamos que el documento anterior se encuentra en la coleccióndb.people. Cómo eliminar el tercer elemento de la intereses matriz por su índice?En MongoDB, ¿cómo eliminar un elemento de matriz por su índice

Editar:

Esta es mi solución actual:

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

¿Hay una manera más directa?

+0

https://docs.mongodb.org/manual/reference/operator/update/pull/ – userMod2

Respuesta

114

No hay una forma directa de tirar/eliminar por índice de matriz. De hecho, este es un problema abierto http://jira.mongodb.org/browse/SERVER-1014, puede votar por él.

La solución está utilizando remover $ y $ tirón:

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

Actualización: como se menciona en algunos de los comentarios que este enfoque no es atómico y puede causar algunas condiciones de carrera si otros clientes leer y/o escribir entre las dos operaciones. Si necesitamos que la operación sea atómica, podríamos:

  • Leer el documento de la base de datos de
  • actualización del documento y quitar el elemento de la matriz
  • Vuelva a colocar el documento en la base de datos. Para asegurar que el documento no ha cambiado desde que lo leemos, podemos utilizar la actualización si el patrón actual describe in the mongo docs
+27

ha sido un año y medio? ¿Sigue siendo este el estado de las cosas con mongodb? – Abe

+0

La siguiente respuesta es más directa y funcionó para mí. Aunque no se elimina por índice, sino que se elimina por valor. – vish

+1

@Javier: ¿esta solución no lo dejaría abierto a problemas si el db cambiara entre el momento en que contó la posición en el índice y el momento en que lo hizo? – UpTheCreek

18

Puede utilizar $pull modificador de update operación para eliminar un elemento particular en una matriz. En caso de que ya ha proporcionado una consulta se verá así:

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

Además, es posible considerar el uso de $pullAll para la eliminación de todas las ocurrencias. Más sobre esto en la página de documentación oficial - http://www.mongodb.org/display/DOCS/Updating#Updating-%24pull

Esto no usa el índice como criterio para eliminar un elemento, pero podría ayudar en casos similares a los suyos. IMO, usar índices para direccionar elementos dentro de una matriz no es muy confiable ya que mongodb no es consistente en el orden de elementos tan rápido como yo sé.

+5

Su elemento es una matriz en la pregunta. Mongo es consistente en el orden en este caso. De hecho, todos los documentos son realmente colecciones ordenadas, pero muchos controladores no los manejan de esta manera. Para complicar aún más el asunto, si un documento debe moverse después de una operación de actualización (debido al crecimiento más allá del factor de relleno), el orden de las teclas se vuelve alfabético (debajo de las coberturas, creo que están ordenadas por su valor binario, esta sospecha basado en mi conocimiento de que las matrices son documentos bastante estándar con claves que son enteros consecutivos en lugar de cadenas). – marr75

+0

Esto evita los problemas de unset + pull, pero requiere que su diccionario esté estrictamente ordenado. Los diccionarios en la mayoría de los idiomas están desordenados, por lo que puede ser complicado hacer que esto suceda. –

+0

@ marr75: ¿Tiene alguna referencia? Siempre se supone que los documentos de Mongo mantienen el orden, y si alguna vez reordenaba subdocumentos, muchas cosas se romperían. –

2

Recomendaría usar un campo GUID (tiendo a usar Object ID), o un campo de incremento automático para cada subdocumento en la matriz.

Con este GUID es fácil emitir un $ pull y asegúrese de extraer el correcto. Lo mismo ocurre con otras operaciones de matriz.

0

En lugar de utilizar el desarmado (como en la respuesta aceptada), resuelvo esto estableciendo el campo en un valor único (es decir, no NULO) y luego tirando de ese valor inmediatamente. Un poco más seguro desde una perspectiva asincrónica. Aquí está el código:

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

suerte mongo se ocupará de esto, tal vez mediante la ampliación del modificador de posición para apoyar $ $ tirar, así como $ empujón.

1

En lugar de usar $ pull, podemos usar $ pop para eliminar elementos en una matriz por su índice. Pero debe restar 1 de la posición del índice para eliminar según el índice.

Por ejemplo, si desea eliminar el elemento en el índice 0 se debe utilizar -1, para el índice 1 se debe utilizar 0 y así sucesivamente ...

consulta para quitar tercera Elemento (aparatos):

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

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

+0

De acuerdo con la documentación vinculada, '$ pop' solo puede eliminar el primer elemento o el último de la matriz. La consulta en esta respuesta no elimina el tercer elemento. –

Cuestiones relacionadas