programing

MongoDB에서 동등한 SQL Join을 실행하려면 어떻게 해야 합니까?

muds 2023. 3. 22. 22:16
반응형

MongoDB에서 동등한 SQL Join을 실행하려면 어떻게 해야 합니까?

MongoDB에서 동등한 SQL Join을 실행하려면 어떻게 해야 합니까?

예를 들어, 두 개의 컬렉션(사용자 및 주석)이 있으며 각 컬렉션에 대한 사용자 정보와 함께 pid=444인 모든 주석을 가져오려고 합니다.

comments
  { uid:12345, pid:444, comment="blah" }
  { uid:12345, pid:888, comment="asdf" }
  { uid:99999, pid:444, comment="qwer" }

users
  { uid:12345, name:"john" }
  { uid:99999, name:"mia"  }

특정 필드(...find({pid:444) 등)와 각 코멘트에 관련된 사용자 정보를 한 번에 가져올 수 있는 방법이 있습니까?

현재, 우선 제 기준에 맞는 코멘트를 취득하고, 그 결과 세트내의 모든 uid를 파악해, 유저 오브젝트를 취득해, 코멘트의 결과와 결합하고 있습니다.내가 잘못하고 있는 것 같아.

Mongo 3.2에서 이 질문에 대한 답은 대부분 정확하지 않습니다.집약 파이프라인에 추가된 새로운 $lookup 연산자는 기본적으로 왼쪽 외부 결합과 동일합니다.

https://docs.mongodb.org/master/reference/operator/aggregation/lookup/ #pipe._S_조회

문서에서:

{
   $lookup:
     {
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     }
}

물론 Mongo는 관계형 데이터베이스가 아니며 개발자들은 $lookup에 대한 특정 사용 사례를 추천하는 데 신중하지만, 적어도 3.2부터는 MongoDB에 가입할 수 있게 되었습니다.

mongodb 클라이언트 콘솔을 사용하여 간단한 기능으로 하나의 컬렉션 내의 모든 데이터를 Marge/Join할 수 있으며, 원하는 쿼리를 실행할 수 있게 되었습니다.완전한 예를 다음에 제시하겠습니다.

.- 작성자:

db.authors.insert([
    {
        _id: 'a1',
        name: { first: 'orlando', last: 'becerra' },
        age: 27
    },
    {
        _id: 'a2',
        name: { first: 'mayra', last: 'sanchez' },
        age: 21
    }
]);

.- 카테고리:

db.categories.insert([
    {
        _id: 'c1',
        name: 'sci-fi'
    },
    {
        _id: 'c2',
        name: 'romance'
    }
]);

.- 서적

db.books.insert([
    {
        _id: 'b1',
        name: 'Groovy Book',
        category: 'c1',
        authors: ['a1']
    },
    {
        _id: 'b2',
        name: 'Java Book',
        category: 'c2',
        authors: ['a1','a2']
    },
]);

- 도서 대출

db.lendings.insert([
    {
        _id: 'l1',
        book: 'b1',
        date: new Date('01/01/11'),
        lendingBy: 'jose'
    },
    {
        _id: 'l2',
        book: 'b1',
        date: new Date('02/02/12'),
        lendingBy: 'maria'
    }
]);

.- 마법:

db.books.find().forEach(
    function (newBook) {
        newBook.category = db.categories.findOne( { "_id": newBook.category } );
        newBook.lendings = db.lendings.find( { "book": newBook._id  } ).toArray();
        newBook.authors = db.authors.find( { "_id": { $in: newBook.authors }  } ).toArray();
        db.booksReloaded.insert(newBook);
    }
);

.- 새 수집 데이터 가져오기:

db.booksReloaded.find().pretty()

.- 응답:)

{
    "_id" : "b1",
    "name" : "Groovy Book",
    "category" : {
        "_id" : "c1",
        "name" : "sci-fi"
    },
    "authors" : [
        {
            "_id" : "a1",
            "name" : {
                "first" : "orlando",
                "last" : "becerra"
            },
            "age" : 27
        }
    ],
    "lendings" : [
        {
            "_id" : "l1",
            "book" : "b1",
            "date" : ISODate("2011-01-01T00:00:00Z"),
            "lendingBy" : "jose"
        },
        {
            "_id" : "l2",
            "book" : "b1",
            "date" : ISODate("2012-02-02T00:00:00Z"),
            "lendingBy" : "maria"
        }
    ]
}
{
    "_id" : "b2",
    "name" : "Java Book",
    "category" : {
        "_id" : "c2",
        "name" : "romance"
    },
    "authors" : [
        {
            "_id" : "a1",
            "name" : {
                "first" : "orlando",
                "last" : "becerra"
            },
            "age" : 27
        },
        {
            "_id" : "a2",
            "name" : {
                "first" : "mayra",
                "last" : "sanchez"
            },
            "age" : 21
        }
    ],
    "lendings" : [ ]
}

이 대사가 도움이 되길 바랍니다.

공식 mongodb 사이트의 이 페이지는 정확히 다음 질문에 대처하고 있습니다.

https://mongodb-documentation.readthedocs.io/en/latest/ecosystem/tutorial/model-data-for-ruby-on-rails.html

스토리 목록을 표시할 때 스토리를 게시한 사용자의 이름을 표시해야 합니다.관계형 데이터베이스를 사용하는 경우 사용자 및 스토어에 대한 가입을 수행하여 단일 쿼리로 모든 개체를 가져올 수 있습니다.그러나 MongoDB는 조인을 지원하지 않기 때문에 때때로 정규화를 해제해야 합니다.여기서 이것은 'username' 속성을 캐시하는 것을 의미합니다.

관계 순결론자들은 이미 우리가 어떤 보편적인 법칙을 위반하고 있는 것처럼 불안해하고 있을지도 모른다.그러나 MongoDB 컬렉션은 관계형 테이블과 동등하지 않으며 각각 고유한 설계 목표를 달성한다는 점에 유의하십시오.정규화된 테이블은 원자적으로 분리된 데이터 청크를 제공합니다.그러나 문서는 개체 전체를 더 가깝게 나타냅니다.소셜 뉴스 사이트의 경우는, 유저명이 투고되는 기사에 고유의 것이라고 주장할 수 있다.

당신이 설명한 대로 해야 합니다.MongoDB는 비관계형 데이터베이스이며 조인을 지원하지 않습니다.

$lookup, $project$match 적절히 조합하면 여러 파라미터로 여러 테이블을 결합할 수 있습니다.여러 번 체인으로 묶일 수 있기 때문입니다.

다음을 수행한다고 가정합니다(참조).

SELECT S.* FROM LeftTable S
LEFT JOIN RightTable R ON S.ID = R.ID AND S.MID = R.MID  
WHERE R.TIM > 0 AND S.MOB IS NOT NULL

순서 1: 모든 테이블 링크

원하는 만큼 많은 테이블을 얻을 수 있습니다.

$120 - 쿼리의 각 테이블당1개

$sqind - 데이터가 올바르게 정규화되지 않으면 어레이로 포장됩니다.

Python 코드..

db.LeftTable.aggregate([
                        # connect all tables

                        {"$lookup": {
                          "from": "RightTable",
                          "localField": "ID",
                          "foreignField": "ID",
                          "as": "R"
                        }},
                        {"$unwind": "R"}
                   
                        ])

순서 2: 모든 조건의 정의

$project : 여기서 모든 조건문과 선택할 모든 변수를 정의합니다.

Python 코드..

db.LeftTable.aggregate([
                        # connect all tables

                        {"$lookup": {
                          "from": "RightTable",
                          "localField": "ID",
                          "foreignField": "ID",
                          "as": "R"
                        }},
                        {"$unwind": "R"},

                        # define conditionals + variables

                        {"$project": {
                          "midEq": {"$eq": ["$MID", "$R.MID"]},
                          "ID": 1, "MOB": 1, "MID": 1
                        }}
                        ])

순서 3: 모든 조건 결합

$match - OR 또는 AND 등을 사용하여 모든 조건에 참여합니다.이것들은 여러 개일 수 있습니다.

$project: 모든 조건의 정의 해제

완전한 Python 코드..

db.LeftTable.aggregate([
                        # connect all tables

                        {"$lookup": {
                          "from": "RightTable",
                          "localField": "ID",
                          "foreignField": "ID",
                          "as": "R"
                        }},
                        {"$unwind": "$R"},

                        # define conditionals + variables

                        {"$project": {
                          "midEq": {"$eq": ["$MID", "$R.MID"]},
                          "ID": 1, "MOB": 1, "MID": 1
                        }},

                        # join all conditionals

                        {"$match": {
                          "$and": [
                            {"R.TIM": {"$gt": 0}}, 
                            {"MOB": {"$exists": True}},
                            {"midEq": {"$eq": True}}
                        ]}},

                        # undefine conditionals

                        {"$project": {
                          "midEq": 0
                        }}

                        ])

테이블, 조건 및 조인의 거의 모든 조합이 이 방법으로 수행될 수 있습니다.

3.2 버전에서 제공되는 룩업을 이용하여 몽고에서 두 컬렉션에 가입할 수 있습니다.당신의 경우 질문은 다음과 같습니다.

db.comments.aggregate({
    $lookup:{
        from:"users",
        localField:"uid",
        foreignField:"uid",
        as:"users_comments"
    }
})

또는, 유저에 관해서도 가입할 수 있습니다.그러면 아래와 같이 약간의 변경이 있을 것입니다.

db.users.aggregate({
    $lookup:{
        from:"comments",
        localField:"uid",
        foreignField:"uid",
        as:"users_comments"
    }
})

SQL의 좌우 조인과 동일하게 동작합니다.

다른 사람들이 지적했듯이, 실제로는 원하지 않는 관계형 데이터베이스에서 관계형 데이터베이스를 작성하려고 합니다.그러나 어쨌든, 이 작업을 실시할 필요가 있는 경우는, 여기서 사용할 수 있는 솔루션이 됩니다.먼저 컬렉션 A(또는 당신의 경우 사용자)에 대해 검색한 후 오브젝트 속성을 사용하여 두 번째 컬렉션(당신의 경우 uid)에서 검색한 후 일치하는 항목이 있으면 인쇄하거나 작업을 수행할 수 있습니다.도움이 되시길 바라며 행운을 빕니다:)

db.users.find().forEach(
function (object) {
    var commonInBoth=db.comments.findOne({ "uid": object.uid} );
    if (commonInBoth != null) {
        printjson(commonInBoth) ;
        printjson(object) ;
    }else {
        // did not match so we don't care in this case
    }
});

다음은 "참가" * 배우영화 컬렉션의 예입니다.

https://github.com/mongodb/cookbook/blob/master/content/patterns/pivot.txt

그것은 을 이용한다..mapReduce()

* join - 문서 지향 데이터베이스에 가입할 수 있는 대안

$140 (정보)

동일한 데이터베이스의 분할되지 않은 컬렉션에 대해 왼쪽 외부 조인을 수행하여 "조인트된" 컬렉션의 문서를 필터링하여 처리합니다.$lookup 단계는 각 입력 문서에 대해 "조인트된" 컬렉션의 일치하는 문서가 요소인 새로운 배열 필드를 추가합니다.$lookup 단계는 이러한 재구성된 문서를 다음 단계로 전달합니다.$lookup 스테이지에는 다음 구문이 있습니다.

평등 매치

입력 문서의 필드와 "가입된" 집합 문서의 필드를 동일하게 일치시키기 위해 $lookup 단계는 다음 구문을 사용합니다.

{
   $lookup:
     {
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     }
}

이 조작은 다음 의사 SQL 문에 대응합니다.

SELECT *, <output array field>
FROM collection
WHERE <output array field> IN (SELECT <documents as determined from the pipeline>
                               FROM <collection to join>
                               WHERE <pipeline> );

Mongo URL

당신이 무엇을 하려고 하는가에 달렸어요.

현재 정규화된 데이터베이스로 설정되어 있으며, 이는 정상이며, 적절한 방법입니다.

하지만, 그것을 하는 다른 방법들이 있다.

각 투고에 코멘트를 삽입한 투고 컬렉션과 반복적으로 쿼리하여 얻을 수 있는 사용자에 대한 참조를 포함할 수 있습니다.주석과 함께 사용자 이름을 저장할 수 있으며, 모두 하나의 문서에 저장할 수 있습니다.

NoSQL은 유연한 스키마와 매우 빠른 읽기 및 쓰기를 위해 설계되었습니다.일반적인 빅데이터 팜에서는 데이터베이스가 가장 큰 병목현상으로 애플리케이션 및 프런트 엔드 서버보다 데이터베이스 엔진 수가 적습니다.더 비싸지만 더 강력하며 하드 드라이브 공간도 비교적 저렴합니다.정규화는 공간을 절약하려는 개념에서 비롯되지만, 데이터베이스로 복잡한 Join을 실행하고 관계의 무결성을 검증하고 캐스케이드 작업을 수행하는 데 비용이 많이 듭니다.데이터베이스를 올바르게 설계하면 개발자의 번거로움을 덜 수 있습니다.

NoSQL에서는 비용(업데이트에 필요한 프로세서 시간과 추가 데이터 저장에 필요한 하드 드라이브 비용 모두) 때문에 용장성과 스토리지 공간이 문제가 되지 않는다는 것을 인정하면 정규화 해제는 문제가 되지 않습니다(수십만 개의 항목이 되는 임베디드 어레이의 경우 성능 문제가 될 수 있습니다).하지만 대부분의 경우 문제가 되지 않습니다.또한 각 데이터베이스 클러스터에는 여러 개의 애플리케이션과 프런트 엔드 서버가 있습니다.참가자의 부하를 높여 데이터베이스 서버가 읽기 및 쓰기를 계속하도록 합니다.

TL;DR: 당신이 하고 있는 일은 괜찮아요. 그리고 다른 방법이 있어요.mongodb 설명서의 데이터 모델 패턴에서 몇 가지 좋은 예를 확인하십시오.http://docs.mongodb.org/manual/data-modeling/

많은 드라이버가 DBRef라고 하는 사양을 지원하고 있습니다.

DBRef는 문서 간에 참조를 작성하기 위한 보다 공식적인 사양입니다.DBRef(일반적으로)에는 컬렉션 이름과 개체 ID가 포함됩니다.대부분의 개발자는 컬렉션을 문서 간에 변경할 수 있는 경우에만 DBRef를 사용합니다.참조된 컬렉션이 항상 같은 경우 위에서 설명한 수동 참조가 더 효율적입니다.

MongoDB 매뉴얼에서 인용:[ Data Models ]> [ Data Model Reference ]> [ Database References ]

3.2.6 이전 Mongodb는 mysql.와 같은 조인 쿼리를 지원하지 않습니다.

 db.getCollection('comments').aggregate([
        {$match : {pid : 444}},
        {$lookup: {from: "users",localField: "uid",foreignField: "uid",as: "userData"}},
   ])

Postgres에서 mongo_fdw를 사용하여 MongoDB에서 join을 포함한 SQL 쿼리를 실행할 수 있습니다.

MongoDB는 가입을 허용하지 않지만 플러그인을 사용하여 이를 처리할 수 있습니다.plugin.mongo-join을 합니다.츠키노을 사용하여 직접 할 수 .npm install mongo-join예시와 함께 전체 문서를 확인할 수 있습니다.

(+) 컬렉션에 참여해야 할 때 매우 유용한 도구

(--) 쿼리 최상위 레벨에만 조건을 적용할 수 있습니다.

var Join = require('mongo-join').Join, mongodb = require('mongodb'), Db = mongodb.Db, Server = mongodb.Server;
db.open(function (err, Database) {
    Database.collection('Appoint', function (err, Appoints) {

        /* we can put conditions just on the top level */
        Appoints.find({_id_Doctor: id_doctor ,full_date :{ $gte: start_date },
            full_date :{ $lte: end_date }}, function (err, cursor) {
            var join = new Join(Database).on({
                field: '_id_Doctor', // <- field in Appoints document
                to: '_id',         // <- field in User doc. treated as ObjectID automatically.
                from: 'User'  // <- collection name for User doc
            }).on({
                field: '_id_Patient', // <- field in Appoints doc
                to: '_id',         // <- field in User doc. treated as ObjectID automatically.
                from: 'User'  // <- collection name for User doc
            })
            join.toArray(cursor, function (err, joinedDocs) {

                /* do what ever you want here */
                /* you can fetch the table and apply your own conditions */
                .....
                .....
                .....


                resp.status(200);
                resp.json({
                    "status": 200,
                    "message": "success",
                    "Appoints_Range": joinedDocs,


                });
                return resp;


            });

    });

집약 파이프라인을 사용하여 작업을 수행할 수 있지만 직접 작성하는 것은 번거로운 일입니다.

를 사용하여 쿼리에서 집계 파이프라인을 자동으로 만들 수 있습니다.

쿼리는 다음과 같습니다.

const mongoose = require("mongoose");
const joinQuery = require("mongo-join-query");

joinQuery(
    mongoose.models.Comment,
    {
        find: { pid:444 },
        populate: ["uid"]
    },
    (err, res) => (err ? console.log("Error:", err) : console.log("Success:", res.results))
);

가 " " "에 .uid을 사용하다을 사용법이것은 팀을 참조하거나 다른 것을 참조하거나 하는 등입니다.

면책사항:나는 썼다mongo-join-query바로 이 문제를 해결하려고요

playORM은 파티션 내에서 조인할 수 있도록 파티션만 추가하는 S-SQL(Scalable SQL)을 사용하여 이를 수행할 수 있습니다.

아뇨, 잘못하고 있는 것 같지 않아요.MongoDB 가입은 "클라이언트 측"입니다.네가 말한 대로야

현재, 우선 제 기준에 맞는 코멘트를 취득하고, 그 결과 세트내의 모든 uid를 파악해, 유저 오브젝트를 취득해, 코멘트의 결과와 결합하고 있습니다.내가 잘못하고 있는 것 같아.

1) Select from the collection you're interested in.
2) From that collection pull out ID's you need
3) Select from other collections
4) Decorate your original results.

실제 조인은 아니지만 원래 선택한 세트를 장식하는 대신 "다수" 측면 조인에 중복 행을 처리할 필요가 없기 때문에 SQL 조인보다 훨씬 유용합니다.

이 페이지에는 허튼소리와 FUD가 많이 있다.5년이 지난 지금도 MongoDB는 여전히 문제가 되고 있습니다.

표준화된 데이터 테이블이 필요한 경우 다른 데이터베이스 솔루션을 사용해 보십시오.

그런데 Git에서 MONGO를 위한 Sollation을 발견했습니다. 그런데 삽입 코드에는 영화 이름이 있지만 noi 무비의 ID가 있습니다.

문제

당신은 그들이 만든 영화들을 가진 배우들의 컬렉션을 가지고 있다.

각각에 배우 배열이 있는 영화 컬렉션을 생성하려고 합니다.

일부 샘플 데이터

 db.actors.insert( { actor: "Richard Gere", movies: ['Pretty Woman', 'Runaway Bride', 'Chicago'] });
 db.actors.insert( { actor: "Julia Roberts", movies: ['Pretty Woman', 'Runaway Bride', 'Erin Brockovich'] });

솔루션

Actor 문서의 각 영화를 루프하고 각 영화를 개별적으로 내보내야 합니다.

여기서 어획량은 감소 단계입니다.축소 단계에서는 어레이를 내보낼 수 없으므로 반환되는 "값" 문서 내에 Actors 어레이를 구축해야 합니다.

The code
map = function() {
  for(var i in this.movies){
    key = { movie: this.movies[i] };
    value = { actors: [ this.actor ] };
    emit(key, value);
  }
}

reduce = function(key, values) {
  actor_list = { actors: [] };
  for(var i in values) {
    actor_list.actors = values[i].actors.concat(actor_list.actors);
  }
  return actor_list;
}

actor_list가 실제로 배열을 포함하는 javascript 객체인 것에 주목하십시오.또한 지도는 동일한 구조를 방출합니다.

다음 명령을 실행하여 맵/축소를 실행하고 "pivot" 컬렉션에 출력한 후 결과를 인쇄합니다.

printjson(db.actors.mapReduce(map, reduce, "pivot")), db.pivot.find().each(printjson);

다음은 샘플 출력입니다. "예쁜 여자"와 "런어웨이 브라이드"에는 "리처드 기어"와 "줄리아 로버츠"가 모두 포함되어 있습니다.

{ "_id" : { "movie" : "Chicago" }, "value" : { "actors" : [ "Richard Gere" ] } }
{ "_id" : { "movie" : "Erin Brockovich" }, "value" : { "actors" : [ "Julia Roberts" ] } }
{ "_id" : { "movie" : "Pretty Woman" }, "value" : { "actors" : [ "Richard Gere", "Julia Roberts" ] } }
{ "_id" : { "movie" : "Runaway Bride" }, "value" : { "actors" : [ "Richard Gere", "Julia Roberts" ] } }

mongoDB 서브 쿼리를 사용하여 두 컬렉션을 병합할 수 있습니다.다음은 Comments의 예시입니다.

`db.commentss.insert([
  { uid:12345, pid:444, comment:"blah" },
  { uid:12345, pid:888, comment:"asdf" },
  { uid:99999, pid:444, comment:"qwer" }])`

사용자--

db.userss.insert([
  { uid:12345, name:"john" },
  { uid:99999, name:"mia"  }])

JOIN에 대한 MongoDB 하위 쿼리--

`db.commentss.find().forEach(
    function (newComments) {
        newComments.userss = db.userss.find( { "uid": newComments.uid } ).toArray();
        db.newCommentUsers.insert(newComments);
    }
);`

새로 생성된 컬렉션에서 결과를 가져옵니다.

db.newCommentUsers.find().pretty()

결과--

`{
    "_id" : ObjectId("5511236e29709afa03f226ef"),
    "uid" : 12345,
    "pid" : 444,
    "comment" : "blah",
    "userss" : [
        {
            "_id" : ObjectId("5511238129709afa03f226f2"),
            "uid" : 12345,
            "name" : "john"
        }
    ]
}
{
    "_id" : ObjectId("5511236e29709afa03f226f0"),
    "uid" : 12345,
    "pid" : 888,
    "comment" : "asdf",
    "userss" : [
        {
            "_id" : ObjectId("5511238129709afa03f226f2"),
            "uid" : 12345,
            "name" : "john"
        }
    ]
}
{
    "_id" : ObjectId("5511236e29709afa03f226f1"),
    "uid" : 99999,
    "pid" : 444,
    "comment" : "qwer",
    "userss" : [
        {
            "_id" : ObjectId("5511238129709afa03f226f3"),
            "uid" : 99999,
            "name" : "mia"
        }
    ]
}`

이게 도움이 되길 바라.

언급URL : https://stackoverflow.com/questions/2350495/how-do-i-perform-the-sql-join-equivalent-in-mongodb

반응형