vacio programacion operadores logicos lenguaje funciones filas estadistica español ejemplos crear contar comandos r mongodb rmongodb nosql

programacion - manual de r estadistica en español



Uso múltiple del operador posicional `$` para actualizar matrices anidadas (2)

Esta pregunta está estrechamente relacionada con esta y consideraré los consejos dados con respecto al diseño del esquema en un contexto NoSQL, pero tengo curiosidad por comprender esto:

Preguntas reales

Supongamos que tiene el siguiente documento:

_id : 2 abcd name : 2 unittest.com paths : 4 0 : 3 path : 2 home queries : 4 0 : 3 name : 2 query1 url : 2 www.unittest.com/home?query1 requests: 4 1 : 3 name : 2 query2 url : 2 www.unittest.com/home?query2 requests: 4

Básicamente, me gustaría saber

  1. si es posible usar el operador $ posicional de MongoDB ( detalles ) varias veces, o ponerlo de otra manera, en escenarios de actualización que involucran estructuras de matriz / documento con un "grado de anidamiento" mayor que 1:

    { <update operator>: { "paths.$.queries.$.requests" : value } } ( no funciona )

    en lugar de "solo", puede usar $ una vez para una matriz de nivel superior y estar obligado a usar índices explícitos para matrices en "niveles superiores":

    { <update operator>: { "paths.$.queries.0.requests" : value } } ) ( funciona )

  2. si es posible, cómo sería la sintaxis R correspondiente.

A continuación encontrará un ejemplo reproducible. Traté de ser lo más conciso posible.

Ejemplo de código

Conexión a la base

require("rmongodb") db <- "__unittest" ns <- paste(db, "hosts", sep=".") # CONNCETION OBJECT con <- mongo.create(db=db) # ENSURE EMPTY DB mongo.remove(mongo=con, ns=ns)

Documento de ejemplo

q <- list("_id"="abcd") b <- list("_id"="abcd", name="unittest.com") mongo.insert(mongo=con, ns=ns, b=b) q <- list("_id"="abcd") b <- list("$push"=list(paths=list(path="home"))) mongo.update(mongo=con, ns, criteria=q, objNew=b) q <- list("_id"="abcd", paths.path="home") b <- list("$push"=list("paths.$.queries"=list( name="query1", url="www.unittest.com/home?query1"))) mongo.update(mongo=con, ns, criteria=q, objNew=b) b <- list("$push"=list("paths.$.queries"=list( name="query2", url="www.unittest.com/home?query2"))) mongo.update(mongo=con, ns, criteria=q, objNew=b)

Actualización de matrices anidadas con índice de posición explícito (trabajos)

Esto funciona, pero implica un índice explícito para las queries matriz de segundo nivel (anidadas en un elemento subdoc de paths de matriz):

q <- list("_id"="abcd", paths.path="home", paths.queries.name="query1") b <- list("$push"=list("paths.$.queries.0.requests"=list(time="2013-02-13"))) > mongo.bson.from.list(b) $push : 3 paths.$.queries.0.requests : 3 time : 2 2013-02-13 mongo.update(mongo=con, ns, criteria=q, objNew=b) res <- mongo.find.one(mongo=con, ns=ns, query=q) > res _id : 2 abcd name : 2 unittest.com paths : 4 0 : 3 path : 2 home queries : 4 0 : 3 name : 2 query1 requests : 4 0 : 3 time : 2 2013-02-13 url : 2 www.unittest.com/home?query1 1 : 3 name : 2 query2 url : 2 www.unittest.com/home?query2

Actualización de matrices anidadas con índices $ posicionales (no funciona)

Ahora, me gustaría sustituir el 0 explícito con el operador posicional $ tal como lo hice para que el servidor encuentre el elemento subdoc deseado de las rutas de los vectores ( paths.$.queries ).

AFAIU la documentación , esto debería funcionar ya que lo crucial es especificar un selector de consultas "correcto":

El operador $ posicional, cuando se usa con el método update () y actúa como un marcador de posición para la primera coincidencia del selector de consulta de actualización:

Creo que especifiqué un selector de consultas que encuentra el elemento anidado correcto (debido a la parte paths.queries.name="query1" ):

q <- list("_id"="abcd", paths.path="home", paths.queries.name="query1")

Supongo que traducido a la sintaxis "MongoDB simple", el selector de consultas se parece algo a esto

{ _id: abcd, paths.path: home, paths.queries.name: query1 }

que me parece un selector de consulta válido. De hecho, coincide con el elemento / documento deseado:

> !is.null(mongo.find.one(mongo=con, ns=ns, query=q)) [1] TRUE

Mi idea era que si funciona en el nivel superior, ¿por qué no debería funcionar también para niveles más altos (siempre que el selector de consultas apunte a los componentes anidados a la derecha)?

Sin embargo, al servidor no parece gustarle un uso anidado o múltiple de $ :

b <- list("$push"=list("paths.$.queries.$.requests"=list(time="2013-02-14"))) > mongo.bson.from.list(b) $push : 3 paths.$.queries.$.requests : 3 time : 2 2013-02-14 > mongo.update(mongo=con, ns, criteria=q, objNew=b) [1] FALSE

No estoy seguro de si no funciona porque MongoDB no es compatible con esto o si no obtuve la sintaxis R correcta.


El operador posicional solo admite un nivel de profundidad y solo el primer elemento coincidente.

Existe un JIRA rastreable para el tipo de comportamiento que desea aquí: https://jira.mongodb.org/browse/SERVER-831

No estoy seguro de si permitirá más de un partido, pero creo que lo hará debido a la dinámica de cómo tendrá que funcionar.


En caso de que pueda ejecutar su consulta desde el shell de MongoDB, puede eludir esta limitación aprovechando el cursor de MongoDB para cada función ( http://docs.mongodb.org/manual/reference/method/cursor.forEach/ )

Aquí hay un ejemplo con 3 matrices anidadas:

var collectionNameCursor = db.collection_name.find({...}); collectionNameCursor.forEach(function(collectionDocument) { var firstArray = collectionDocument.firstArray; for(var i = 0; i < firstArray.length; i++) { var secondArray = firstArray[i].secondArray; for(var j = 0; j < secondArray.length; j++) { var thirdArray = secondArray[j].thirdArray; for(var k = 0; k < thirdArray.length; k++) { //... do some logic here with thirdArray''s elements db.collection_name.save(collectionDocument); } } } });

Tenga en cuenta que esto es más una solución de una sola vez que un código de producción, pero hará el trabajo si tiene que escribir un script de reparación.