MongoDB의 $ unwind 연산자는 무엇입니까?


103

이것은 MongoDB와의 첫날이므로 나와 함께 쉽게 가십시오 :)

$unwind영어가 모국어가 아니기 때문에 연산자를 이해할 수 없습니다 .

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

프로젝트 운영자는 내가 이해할 수있는 것 SELECT입니다 (같지 않습니까?). 그러나 $unwind(citing) 은 모든 소스 문서 내에서 풀린 배열의 모든 구성원에 대해 하나의 문서를 반환합니다 .

이건 JOIN어때? 그렇다면, 방법의 결과 $project(와 _id, author, titletags필드)가 비교 될 수있다 tags배열?

참고 : MongoDB 웹 사이트에서 예제를 가져 왔지만 tags배열 의 구조를 모릅니다 . 태그 이름의 단순한 배열이라고 생각합니다.

답변:


236

먼저 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
}

결과 배열에서 변경되는 유일한 것은 tags 값에서 반환되는 것입니다. 작동 방식에 대한 추가 참조가 필요한 경우 여기 에 링크를 포함했습니다 . 이것이 도움이되기를 바라며, 지금까지 제가 접한 최고의 NoSQL 시스템 중 하나에 대한 귀하의 진출에 행운을 빕니다.


44

$unwind 파이프 라인의 각 문서를 배열 요소 당 한 번씩 복제합니다.

귀하의 의견 파이프 라인이 두 요소를 하나의 문서 문서를 포함 그래서 만약 tags, {$unwind: '$tags'}을 제외하고는 동일한 두 개의 문서 문서로 파이프 라인을 변환 할 tags필드. 첫 번째 문서 tags에는 원본 문서 배열의 첫 번째 요소 tags가 포함되고 두 번째 문서 에는 두 번째 요소가 포함됩니다.


22

예를 들어 이해합시다

어떻게 '이다 회사의 문서는 다음과 같습니다

원본 문서

$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"
    } }
])

unwind는 입력으로받는 것보다 더 많은 문서를 다음 단계로 출력하는 효과가 있습니다.

funding_rounds배열 을 보면 각 funding_rounds에 대해 raised_amountfunded_year필드 가 있음을 알 수 있습니다. 따라서 배열의 unwind요소 인 문서 각각에 대해 funding_rounds출력 문서가 생성됩니다. 이제이 예에서 값은 strings입니다. 그러나 배열의 요소 값 유형에 관계없이는 unwind이러한 값 각각에 대한 출력 문서를 생성하므로 해당 필드에 해당 요소 만 있습니다. 의 경우 funding_rounds해당 요소는 스테이지로 funding_rounds전달되는 모든 문서 의 값으로 이러한 문서 중 하나가 project됩니다. 이것을 실행 한 결과, 이제 우리는 amountyear. 에 대한 하나의 모든 회사에 대한 각각의 자금 조달 라운드우리 컬렉션에서. 이것이 의미하는 바는 우리의 매치가 많은 회사 문서를 생성하고 이러한 회사 문서 각각이 많은 문서를 생성한다는 것입니다. 모든 회사 문서의 각 펀딩 라운드마다 하나씩. 스테이지 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_amountfunded_year필드 가있는 중첩 문서라는 것 입니다. 따라서 필터를 사용하는 project각 회사에 대해 여러 문서를 받게 match되므로 각 문서를 개별적으로 처리하고 각 회사의 각 자금 조달 라운드에 대한 개별 금액과 연도를 식별 할 수 있습니다..


2
같은 문서를 사용하는 것이 더 좋습니다.
Jeb50

1
$ unwind의 첫 번째 사용 사례로 저는 매우 복잡한 중첩 세트 세트를 가졌습니다. mongo 문서와 stackowerflow 사이를 이동하면서 귀하의 답변은 마침내 $ project 및 $ unwind를 더 잘 이해하는 데 도움이되었습니다. 감사합니다 @ Zameer!
7

3

mongodb 공식 문서에 따라 :

$ unwind 입력 문서에서 배열 필드를 분해하여 각 요소에 대한 문서를 출력합니다. 각 출력 문서는 배열 필드의 값이 요소로 대체 ​​된 입력 문서입니다.

기본 예를 통한 설명 :

컬렉션 인벤토리에는 다음과 같은 문서가 있습니다.

{ "_id" : 1, "item" : "ABC", "sizes": [ "S", "M", "L"] }
{ "_id" : 2, "item" : "EFG", "sizes" : [ ] }
{ "_id" : 3, "item" : "IJK", "sizes": "M" }
{ "_id" : 4, "item" : "LMN" }
{ "_id" : 5, "item" : "XYZ", "sizes" : null }

다음 $ unwind 작업은 동일하며 sizes 필드의 각 요소에 대한 문서를 반환 합니다. sizes 필드가 배열로 확인되지 않지만 누락, null 또는 빈 배열이 아닌 경우 $ unwind는 배열이 아닌 피연산자를 단일 요소 배열로 처리합니다.

db.inventory.aggregate( [ { $unwind: "$sizes" } ] )

또는

db.inventory.aggregate( [ { $unwind: { path: "$sizes" } } ] 

위 쿼리 출력 :

{ "_id" : 1, "item" : "ABC", "sizes" : "S" }
{ "_id" : 1, "item" : "ABC", "sizes" : "M" }
{ "_id" : 1, "item" : "ABC", "sizes" : "L" }
{ "_id" : 3, "item" : "IJK", "sizes" : "M" }

왜 필요한가요?

$ unwind는 집계를 수행하는 동안 매우 유용합니다. 복잡한 / 중첩 된 문서를 간단한 문서로 나누고 정렬, 검색 등 다양한 작업을 수행합니다.

$ unwind에 대해 자세히 알아 보려면 :

https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/

집계에 대해 자세히 알아 보려면 다음을 수행하십시오.

https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/


2

컬렉션에서이 데이터를 이해하려면 아래 예를 고려하십시오.

{
        "_id" : 1,
        "shirt" : "Half Sleeve",
        "sizes" : [
                "medium",
                "XL",
                "free"
        ]
}

쿼리-db.test1.aggregate ([{$ unwind : "$ sizes"}]);

산출

{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "medium" }
{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "XL" }
{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "free" }

1

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

$ 프로젝트 / 선택은 단순히 이러한 필드 / 열 등을 반환

기사 에서 작성자, 제목, 태그 선택

다음은 Mongo의 재미있는 부분입니다.이 배열 tags : [ "fun" , "good" , "fun" ]을 "tags"라는 이름의 또 다른 관련 테이블 (값이 일부 중복되기 때문에 조회 / 참조 테이블이 될 수 없음)으로 간주합니다. 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"필드를 생략하도록 지시하지 않았기 때문에 자동으로 추가됩니다.

핵심은 집계를 수행하기 위해 테이블처럼 만드는 것입니다.


또는 그것을 생각하는 또 다른 방법은 UNION ALL입니다
Jeb50
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.