Подтвердить что ты не робот

Что такое оператор $unwind в MongoDB?

Это мой первый день с MongoDB, поэтому, пожалуйста, пройдите со мной:)

Я не могу понять оператора $unwind, возможно, потому что английский не является моим родным языком.

db.article.aggregate(
    { $project : {
        author : 1 ,
        title : 1 ,
        tags : 1
    }},
    { $unwind : "$tags" }
);
Оператор проекта - это то, что я могу понять, я полагаю (это как SELECT, не так ли?). Но тогда $unwind (цитирование) возвращает один документ для каждого члена развернутого массива в каждом исходном документе.

Это как JOIN? Если да, то как результат $project (с полями _id, author, title и tags) можно сравнить с массивом tags?

ПРИМЕЧАНИЕ. Я привел пример с сайта MongoDB, я не знаю структуру массива tags. Я думаю, что это простой массив имен тегов.

4b9b3361

Ответ 1

Прежде всего, добро пожаловать в MongoDB!

Следует помнить, что MongoDB использует "NoSQL" подход к хранению данных, поэтому гибнет мысли о выборе, объединении и т.д. из вашего ума. Способ хранения ваших данных в виде документов и коллекций, что позволяет использовать динамические средства для добавления и получения данных из ваших мест хранения.

При этом, чтобы понять концепцию параметра $unwind, вы должны сначала понять, что говорит пример использования, который вы пытаетесь процитировать. Пример документа из mongodb.org выглядит следующим образом:

{
 title : "this is my title" ,
 author : "bob" ,
 posted : new Date () ,
 pageViews : 5 ,
 tags : [ "fun" , "good" , "fun" ] ,
 comments : [
             { author :"joe" , text : "this is cool" } ,
             { author :"sam" , text : "this is bad" }
 ],
 other : { foo : 5 }
}

Обратите внимание, что теги на самом деле представляют собой массив из 3 элементов, в этом случае это "весело", "хорошо" и "весело".

То, что $unwind делает, позволяет вам очистить документ от каждого элемента и вернуть этот результирующий документ. Чтобы думать об этом в классическом подходе, это было бы равнозначно "для каждого элемента в массиве тегов, вернуть документ только с этим элементом".

Таким образом, результат выполнения:

db.article.aggregate(
    { $project : {
        author : 1 ,
        title : 1 ,
        tags : 1
    }},
    { $unwind : "$tags" }
);

вернет следующие документы:

{
     "result" : [
             {
                     "_id" : ObjectId("4e6e4ef557b77501a49233f6"),
                     "title" : "this is my title",
                     "author" : "bob",
                     "tags" : "fun"
             },
             {
                     "_id" : ObjectId("4e6e4ef557b77501a49233f6"),
                     "title" : "this is my title",
                     "author" : "bob",
                     "tags" : "good"
             },
             {
                     "_id" : ObjectId("4e6e4ef557b77501a49233f6"),
                     "title" : "this is my title",
                     "author" : "bob",
                     "tags" : "fun"
             }
     ],
     "OK" : 1
}

Обратите внимание, что единственное, что меняется в массиве результатов, - это то, что возвращается в значении тегов. Если вам нужна дополнительная ссылка на то, как это работает, я включил ссылку здесь. Надеюсь, это поможет, и удачи с вашим набегом в одну из лучших систем NoSQL, с которыми я до сих пор сталкивался.

Ответ 2

$unwind дублирует каждый документ в конвейере, один раз для элемента массива.

Итак, если ваш входной конвейер содержит один документ статьи с двумя элементами в tags, {$unwind: '$tags'} преобразует конвейер в два документа документа, которые являются теми же, за исключением поля tags. В первом документе tags будет содержать первый элемент из исходного массива doc, а во втором документе tags будет содержать второй элемент.

Ответ 3

Поясним это на примере

Вот как выглядит документ компании:

исходный документ

$unwind позволяет нам принимать документы в качестве входных данных, которые имеют поле с оценкой массива и выдает выходные документы, так что есть один выходной документ для каждого элемента массива. источник

Стадия $unwind

Итак, вернемся к примерам наших компаний и посмотрим на использование этапов размотки. Этот запрос:


db.companies.aggregate([
    { $match: {"funding_rounds.investments.financial_org.permalink": "greylock" } },
    { $project: {
        _id: 0,
        name: 1,
        amount: "$funding_rounds.raised_amount",
        year: "$funding_rounds.funded_year"
    } }
])

создает документы с массивами как для суммы, так и для года.

выход проекта

Потому что мы получаем доступ к увеличенной сумме и финансируемому году для каждого элемента в массиве раундов финансирования. Чтобы исправить это, мы можем включить этап размотки перед нашим этапом проекта в этом конвейере агрегации и параметризовать это, сказав, что мы хотим unwind массив раундов финансирования:


db.companies.aggregate([
    { $match: {"funding_rounds.investments.financial_org.permalink": "greylock" } },
    { $unwind: "$funding_rounds" },
    { $project: {
        _id: 0,
        name: 1,
        amount: "$funding_rounds.raised_amount",
        year: "$funding_rounds.funded_year"
    } }
])

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

Если мы посмотрим на массив funding_rounds, мы знаем, что для каждого funding_rounds существует поле raised_amount и a funded_year. Таким образом, unwind будет для каждого из документов, которые являются элементами массива funding_rounds, создает выходной документ. Теперь в этом примере наши значения string s. Но, независимо от типа значения для элементов в массиве, unwind создаст выходной документ для каждого из этих значений, так что поле, о котором идет речь, будет иметь только этот элемент. В случае funding_rounds этот элемент будет одним из этих документов в качестве значения для funding_rounds для каждого документа, который будет передан на наш этап project. Результатом, после этого, является то, что теперь мы получаем amount и a year. Один для каждого раунда финансирования для каждой компании в нашей коллекции. Это означает, что в нашем матче появилось много документов компании, и каждый из этих документов компании во многих документах. Один для каждого раунда финансирования в каждом документе компании. unwind выполняет эту операцию, используя документы, переданные ей с этапа match. И все эти документы для каждой компании затем передаются на этап project.

отключить вывод

Итак, все документы, в которых спонсор Greylock (как в примере запроса), будут разделены на несколько документов, равных количеству раундов финансирования для каждой компании, которая соответствует фильтру $match: {"funding_rounds.investments.financial_org.permalink": "greylock" }. И каждый из этих результирующих документов будет передан вместе с нашим project. Теперь unwind создает точную копию для каждого из документов, которые он получает в качестве входных данных. Все поля имеют один и тот же ключ и значение, за одним исключением, и что поле funding_rounds вместо массива документов funding_rounds вместо этого имеет значение, которое представляет собой отдельный документ, который представляет собой отдельный раунд финансирования. Таким образом, компания, имеющая раунды финансирования 4, приведет к созданию unwind документов 4. Если каждое поле является точной копией, за исключением поля funding_rounds, которое вместо массива для каждой из этих копий будет вместо этого отдельным элементом из массива funding_rounds из документа компании, который в настоящее время unwind обработка. Таким образом, unwind приводит к тому, что на следующий этап выводится больше документов, чем в качестве входных данных. Это означает, что наш этап project теперь получает поле funding_rounds, которое снова не является массивом, а является вложенным документом, который имеет поле raised_amount и funded_year. Таким образом, project получит несколько документов для каждой компании match фильтра и может поэтому обрабатывать каждый из документов по отдельности и идентифицировать индивидуальную сумму и год для каждого раунда финансирования для каждой компании.

Ответ 4

Позвольте мне объяснить, каким образом переводится в RDBMS. Это утверждение:

db.article.aggregate(
    { $project : {
        author : 1 ,
        title : 1 ,
        tags : 1
    }},
    { $unwind : "$tags" }
);

для применения к документу/записи:

{
 title : "this is my title" ,
 author : "bob" ,
 posted : new Date () ,
 pageViews : 5 ,
 tags : [ "fun" , "good" , "fun" ] ,
 comments : [
             { author :"joe" , text : "this is cool" } ,
             { author :"sam" , text : "this is bad" }
 ],
 other : { foo : 5 }
}

$project/Select просто возвращает эти поля/столбцы как

SELECT автор, заголовок, теги ОТ статья

Далее интересная часть Mongo, рассмотрим этот массив tags : [ "fun" , "good" , "fun" ] как другую связанную таблицу (не может быть поисковой/справочной таблицей, поскольку значения имеют некоторое дублирование) с именем "теги". Помните, что SELECT обычно производит вещи вертикально, поэтому разворачивайте теги split() по вертикали в теги таблицы.

Конечный результат $project + $unwind: введите описание изображения здесь

Перевести вывод на JSON:

{ "author": "bob", "title": "this is my title", "tags": "fun"},
{ "author": "bob", "title": "this is my title", "tags": "good"},
{ "author": "bob", "title": "this is my title", "tags": "fun"}

Потому что мы не сказали Mongo опустить поле "_id", поэтому оно автоматически добавлено.

Ключ должен сделать его похожим на таблицу, чтобы выполнить агрегацию.