Многократное использование позиционного оператора `$` для обновления вложенных массивов

Этот вопрос тесно связан с этим, и я рассмотрю рекомендации, касающиеся дизайна схемы в контексте NoSQL, но мне любопытно это понять:

Актуальные вопросы

Предположим, у вас есть следующий документ:

_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 

В принципе, я хотел бы знать

  1. если можно использовать многопользовательский оператор MongoDB ( подробности ) несколько раз или иначе по-разному в сценариях обновления, которые include структуры массива / документа с «степенью вложенности», превышающей 1:

    { : { "paths.$.queries.$.requests" : value } } ( не работает )

    вместо «only» можно использовать $ once для массива верхнего уровня и привязывать к явным индексам для массивов на «более высоких уровнях»:

    { : { "paths.$.queries.0.requests" : value } } ) ( работает )

  2. если возможно вообще, как будет выглядеть соответствующий синтаксис R.

Ниже вы найдете воспроизводимый пример. Я старался быть максимально лаконичным.


Пример кода

Подключение к базе данных

 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) 

Пример документа

 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) 

Обновление вложенных массивов с явным индексом позиции (работает)

Это работает, но включает явный индекс для queries массива второго уровня (вложенных в элемент subdoc paths массива):

 q <- list("_id"="abcd", paths.path="home", paths.queries.name="query1") b  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  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 

Обновление вложенных массивов с позиционными $ indexes (не работает)

Теперь я хотел бы подставить явный 0 оператором positional $ же, как и я, чтобы сервер нашел нужный элемент subdoc paths массива ( paths.$.queries ).

AFAIU документации , это должно работать, поскольку важно указать «правильный» селектор запросов:

Оператор positional $ при использовании с методом update () и выступает в качестве заполнителя для первого совпадения селектора запросов обновления:

Я думаю, что я определил селектор запросов, который найдет правильный вложенный элемент (из-за части paths.queries.name="query1" ):

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

Я предполагаю, что переводится в синтаксис «простой MongoDB», селектор запросов выглядит примерно так:

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

который походит на действительный селектор запросов для меня. Фактически он соответствует желаемому элементу / doc:

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

Я думал, что если он работает на верхнем уровне, почему он не должен работать и на более высоких уровнях (пока селектор запросов указывает на правильные вложенные компоненты)?

Однако сервер не похоже на nested или многократное использование $ :

 b  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 

Я не уверен, что это не сработает, потому что MongoDB не поддерживает это, или если я не получил синтаксис R.

Оператор позиционирования поддерживает только один уровень глубины и только первый соответствующий элемент.

Существует JIRA для отслеживания поведения, которое вы хотите здесь: https://jira.mongodb.org/browse/SERVER-831

Я не уверен, что это допустит более одного матча, но я верю, что это будет связано с динамикой того, как он будет работать.

Если вы можете выполнить свой запрос из оболочки MongoDB, вы можете обойти это ограничение, воспользовавшись функцией MongoDB для forEach ( http://docs.mongodb.org/manual/reference/method/cursor.forEach/ )

Вот пример с 3 вложенными массивами:

 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); } } } }); 

Обратите внимание, что это скорее одноразовое решение, чем производственный код, но он будет выполнять задание, если вам нужно написать сценарий исправления.

Interesting Posts
Давайте будем гением компьютера.