MongoDB - фильтрация содержимого внутреннего массива в наборе результатов - PullRequest
13 голосов
/ 15 января 2011

Я недавно использую MongoDB, и я не знаю, как решить следующую проблему:

У меня есть такая коллекция документов:

{
 "URL": "www.stackoverflow.com",
 "TAGS": [
         {"NAME": "question", "VOTES": 3},
         {"NAME": "answer", "VOTES": 5},
         {"NAME": "problem", "VOTES": 2}
         ]
}

Прежде всего, я хотел, чтобы все URL-адреса имели все теги, приведенные в списке. Я решил это с помощью запроса:

db.links.find( { "Tags.Name" : { $all: ["question","answers"] } } );

Но этот запрос возвращает весь правильный документ, состоящий только из правильного документа только с тегами, которые я запросил.

Результат, который я ищу:

{
 "URL": "www.stackoverflow.com",
 "TAGS": [{"NAME": "question", "VOTES": 3},
         {"NAME": "answer", "VOTES": 5}]
}

а не:

{
 "URL": "www.stackoverflow.com",
 "TAGS": [{"NAME": "question", "VOTES": 3},
         {"NAME": "answer", "VOTES": 5},
         {"NAME": "problem", "VOTES": 2}]
}

Потому что я спрашивал только о тегах ["вопрос", "ответы"].

Я думал об использовании MapReduce или разборе набора результатов, но я не знаю, является ли это правильным способом решения проблемы. Может быть, есть встроенная функция, которая решает ее более эффективно.

Спасибо!

Ответы [ 5 ]

19 голосов
/ 31 августа 2013

Вы можете использовать структуру агрегации MongoDB.

Если у вас есть документ в вашей коллекции, как;

{
 "URL": "www.stackoverflow.com",
 "TAGS": [
         {"NAME": "question", "VOTES": 3},
         {"NAME": "answer", "VOTES": 5},
         {"NAME": "problem", "VOTES": 2}
         ]
}

и вы хотите отфильтровать некоторые элементы массива, вы можете использовать образец агрегации;

db.sof_table.aggregate
([
{$unwind:'$TAGS'}, 
{$match:{'TAGS.NAME':{$in:['answer','question']}}},
{$group:{_id:'$URL',TAGS:{$push:'$TAGS'}}}
])

Это приведет;

{
    "result" : [
        {
            "_id" : "www.stackoverflow.com",
            "TAGS" : [
                {
                    "NAME" : "question",
                    "VOTES" : 3
                },
                {
                    "NAME" : "answer",
                    "VOTES" : 5
                }
            ]
        }
    ],
    "ok" : 1
}

как ваш ожидаемый результат.

8 голосов
/ 15 января 2011

Вообще говоря, любая операция find() в MongoDB возвращает все документы, соответствующие запросу, и все документы извлекаются полностью. Если вам нужен только определенный раздел документа, то вы должны выполнить эту обработку на стороне клиента.

Это принципиальное различие между базами данных документов и базами данных SQL. Как правило, в базе данных документов запрос возвращает все документы, которые ему соответствуют, тогда как в базе данных SQL вы можете выбрать возврат только частей таблицы. Если, конечно, вы не говорите, что делаете MapReduce, но это похоже на излишество для вашего варианта использования.

Не для того, чтобы отговорить вас от использования MongoDB, но независимо от того, над каким проектом вы работаете, подумайте, действительно ли базы данных NoSQL отвечают всем требованиям (соответствуют ли они требованию, которого не может SQL), или вам все же лучше работать с традиционной базой данных SQL.

3 голосов
/ 16 января 2011

Возможно подавить ключи и элементы массива в возвращаемом документе, но не так, как вы хотите.

В вашем примере вы можете подавить ключ URL с помощью следующего запроса, который используетВторой аргумент для find ():

db.links.find({"TAGS.NAME" : {$all : ["question","answer"]}}, {"URL" : 0})

Однако я не верю, что можно подавить отдельные элементы массива на стороне сервера с помощью find (), в зависимости от того, какие члены массива были указаны с помощью$ all.

Вы можете использовать $ slice для возврата только определенных членов массива, но он основан на позиции.Например,

{$slice : [1, 2]}

пропускает первый элемент массива и возвращает до следующих двух.

0 голосов
/ 28 февраля 2017

Это может помочь вам.

Оператор проекции $ elemMatch принимает явный аргумент условия. Это позволяет проецировать на основе условия, отсутствующего в запросе, или если вам необходимо проецировать на основе нескольких полей во встроенных документах массива. **

https://docs.mongodb.com/manual/reference/operator/projection/elemMatch/

0 голосов
/ 22 февраля 2012

Спасибо, Роберт. Я понял, что то, что я ищу, в данный момент не реализовано. Вот ссылка на вопрос . Я надеюсь, что MongoDB cominuty реализует это в короткие сроки. Спасибо!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...