MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Свързване и създаване на MongoDB Joins с помощта на SQL:Част 2

JOIN е една от ключовите отличителни характеристики между SQL и NoSQL бази данни. В SQL бази данни можем да извършим JOIN между две таблици в една и съща или различни бази данни. Това обаче не е така за MongoDB, тъй като позволява JOIN операции между две колекции в една и съща база данни.

Начинът, по който данните се представят в MongoDB, прави почти невъзможно свързването им от една колекция с друга, освен когато се използват основни функции за заявка на скрипт. MongoDB или денормализира данните, като съхранява свързани елементи в отделен документ, или свързва данни в друг отделен документ.

Човек може да свърже тези данни чрез използване на ръчни препратки като полето _id на един документ, който е записан в друг документ като справка. Независимо от това, човек трябва да направи множество заявки, за да извлече някои необходими данни, което прави процеса малко досаден.

Ето защо ние решаваме да използваме концепцията JOIN, която улеснява връзката на данните. JOIN операцията в MongoDB се постига чрез използването на оператор $lookup, който беше въведен във версия 3.2.

$lookup оператор

Основната идея зад концепцията JOIN е да се получи корелация между данни в една колекция към друга. Основният синтаксис на оператора $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, ние винаги знаем, че резултатът от операция JOIN е отделен ред, свързващ всички полета от локалната и чуждата таблица. За MongoDB това е различен случай, тъй като документите с резултати се добавят като масив от документ за локална колекция. Например, нека имаме две колекции; „ученици“ и „единици“

ученици

{"_id" : 1,"name" : "James Washington","age" : 15.0,"grade" : "A","score" : 10.5}
{"_id" : 2,"name" : "Clinton Ariango","age" : 14.0,"grade" : "B","score" : 7.5}
{"_id" : 3,"name" : "Mary Muthoni","age" : 16.0,"grade" : "A","score" : 11.5}

Единици

{"_id" : 1,"Maths" : "A","English" : "A","Science" : "A","History" : "B"}
{"_id" : 2,"Maths" : "B","English" : "B","Science" : "A","History" : "B"}
{"_id" : 3,"Maths" : "A","English" : "A","Science" : "A","History" : "A"}

Можем да извлечем единиците за ученици със съответните оценки, използвайки оператора $lookup с подхода JOIN .i.e.

db.getCollection('students').aggregate([{
$lookup:
    {
        from: "units",
        localField: "_id",
        foreignField : "_id",
        as: "studentUnits"
    }
}])

Което ще ни даде резултатите по-долу:

{"_id" : 1,"name" : "James Washington","age" : 15,"grade" : "A","score" : 10.5,
    "studentUnits" : [{"_id" : 1,"Maths" : "A","English" : "A","Science" : "A","History" : "B"}]}
{"_id" : 2,"name" : "Clinton Ariango","age" : 14,"grade" : "B","score" : 7.5,
    "studentUnits" : [{"_id" : 2,"Maths" : "B","English" : "B","Science" : "A","History" : "B"}]}
{"_id" : 3,"name" : "Mary Muthoni","age" : 16,"grade" : "A","score" : 11.5,
    "studentUnits" : [{"_id" : 3,"Maths" : "A","English" : "A","Science" : "A","History" : "A"}]}

Както споменахме по-горе, ако направим JOIN с помощта на SQL концепцията, ще бъдем върнати с отделни документи в платформата Studio3T .i.e.

SELECT *
  FROM students
    INNER JOIN units
      ON students._id = units._id

Е еквивалент на

db.getCollection("students").aggregate(
    [
        { 
            "$project" : {
                "_id" : NumberInt(0), 
                "students" : "$$ROOT"
            }
        }, 
        { 
            "$lookup" : {
                "localField" : "students._id", 
                "from" : "units", 
                "foreignField" : "_id", 
                "as" : "units"
            }
        }, 
        { 
            "$unwind" : {
                "path" : "$units", 
                "preserveNullAndEmptyArrays" : false
            }
        }
    ]
);

Горната SQL заявка ще върне резултатите по-долу:

{ "students" : {"_id" : NumberInt(1),"name" : "James Washington","age" : 15.0,"grade" : "A","score" : 10.5}, 
    "units" : {"_id" : NumberInt(1),"Maths" : "A","English" : "A","Science" : "A","History" : "B"}}
{ "students" : {"_id" : NumberInt(2), "name" : "Clinton Ariango","age" : 14.0,"grade" : "B","score" : 7.5 }, 
    "units" : {"_id" : NumberInt(2),"Maths" : "B","English" : "B","Science" : "A","History" : "B"}}
{ "students" : {"_id" : NumberInt(3),"name" : "Mary Muthoni","age" : 16.0,"grade" : "A","score" : 11.5},
"units" : {"_id" : NumberInt(3),"Maths" : "A","English" : "A","Science" : "A","History" : "A"}}

Продължителността на изпълнението очевидно ще зависи от структурата на вашата заявка. Например, ако имате много документи в една колекция над другата, трябва да направите агрегирането от колекцията с по-малко документи и след това да търсите в тази с повече документи. По този начин търсенето на избраното поле от колекцията с по-малки документи е доста оптимално и отнема по-малко време, отколкото извършването на множество търсения за избрано поле в колекцията с повече документи. Затова е препоръчително да поставите по-малката колекция на първо място.

За релационна база данни редът на базите данни няма значение, тъй като повечето интерпретатори на SQL имат оптимизатори, които имат достъп до допълнителна информация, за да решат коя да бъде първа.

В случая с MongoDB ще трябва да използваме индекс, за да улесним операцията JOIN. Всички знаем, че всички документи на MongoDB имат ключ _id, който за релационна DBM може да се счита за първичен ключ. Индексът предоставя по-добър шанс за намаляване на количеството данни, които трябва да бъдат достъпни, освен че поддържа операцията, когато се използва във външния ключ $lookup.

В конвейера за агрегиране, за да използваме индекс, трябва да гарантираме, че $match се извършва на първия етап, за да филтрираме документи, които не отговарят на критериите. Например, ако искаме да извлечем резултата за ученика със стойност на полето _id, равна на 1:

select * 
from students 
  INNER JOIN units 
    ON students._id = units._id 
      WHERE students._id = 1;

Еквивалентният код на MongoDB, който ще получите в този случай, е:

db.getCollection("students").aggregate(
[{"$project" : { "_id" : NumberInt(0), "students" : "$$ROOT" }}, 
     {  "$lookup" : {"localField" : "students._id", "from" : "units",  "foreignField" : "_id",  "as" : "units"} }, 
     { "$unwind" : { "path" : "$units","preserveNullAndEmptyArrays" : false } }, 
      { "$match" : {"students._id" : NumberLong(1) }}
    ]);

Върнатият резултат за заявката по-горе ще бъде:

{"_id" : 1,"name" : "James Washington","age" : 15,"grade" : "A","score" : 10.5,
    "studentUnits" : [{"_id" : 1,"Maths" : "A","English" : "A","Science" : "A","History" : "B"}]}

Когато не използваме етапа $match или по-скоро не на първия етап, ако проверим с функцията за обяснение, ще включим и етапа COLLSCAN. Извършването на COLLSCAN за голям набор от документи обикновено ще отнеме много време. По този начин ние решаваме да използваме индексно поле, което във функцията за обяснение включва само етапа IXSCAN. Последното има предимство, тъй като проверяваме индекс в документите, а не сканираме всички документи; няма да отнеме много време, за да върне резултатите. Може да имате различна структура на данните като:

{    "_id" : NumberInt(1), 
    "grades" : {"Maths" : "A", "English" : "A",  "Science" : "A", "History" : "B"
    }
}

Може да искаме да върнем оценките като различни обекти в масив, а не като цяло вградено поле за оценки.

След като напишем SQL заявката по-горе, трябва да модифицираме получения код на MongoDB. За да направите това, щракнете върху иконата за копиране вдясно, както е по-долу, за да копирате кода за обобщаване:

След това отидете на раздела за обобщаване и в представения панел има икона за поставяне, щракнете върху нея, за да поставите кода.

Щракнете върху реда $match и след това върху зелената стрелка нагоре, за да преместите етапа нагоре като първи етап. Въпреки това, първо ще трябва да създадете индекс във вашата колекция като:

db.students.createIndex(
   { _id: 1 },
   { name: studentId }
)

Ще получите примерния код по-долу:

db.getCollection("students").aggregate(
    [{ "$match" : {"_id" : 1.0}},
  { "$project" : {"_id" : NumberInt(0),"students" : "$$ROOT"}}, 
      { "$lookup" : {"localField" : "students._id","from" : "units","foreignField" : "_id","as" : "units"}}, 
      { "$unwind" : {"path" : "$units", "preserveNullAndEmptyArrays" : false}}
    ]
Severalnines Станете DBA на MongoDB – Пренасяне на MongoDB в Производството Научете какво трябва да знаете, за да внедрите, наблюдавате, управлявате и мащабирате MongoDB Изтеглете безплатно

С този код ще получим резултата по-долу:

{ "students" : {"_id" : NumberInt(1), "name" : "James Washington","age" : 15.0,"grade" : "A", "score" : 10.5}, 
    "units" : {"_id" : NumberInt(1), "grades" : {"Maths" : "A", "English" : "A", "Science" : "A",  "History" : "B"}}}

Но всичко, от което се нуждаем, е да имаме оценките като отделен документен обект в върнатия документ, а не като горния пример. Следователно ще добавим етапа $addfields, следователно кода, както е по-долу.

db.getCollection("students").aggregate(
    [{ "$match" : {"_id" : 1.0}},
  { "$project" : {"_id" : NumberInt(0),"students" : "$$ROOT"}}, 
      { "$lookup" : {"localField" : "students._id","from" : "units","foreignField" : "_id","as" : "units"}}, 
      { "$unwind" : {"path" : "$units", "preserveNullAndEmptyArrays" : false}},
      { "$addFields" : {"units" : "$units.grades"} }]

След това получените документи ще бъдат:

{
"students" : {"_id" : NumberInt(1), "name" : "James Washington", "grade" : "A","score" : 10.5}, 
     "units" : {"Maths" : "A", "English" : "A",  "Science" : "A", "History" : "B"}
}

Върнатите данни са доста изрядни, тъй като елиминирахме вградените документи от колекцията на единиците като отделно поле.

В следващия ни урок ще разгледаме заявки с няколко присъединявания.


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Изпълнете javascript скрипт (.js файл) в mongodb, включително друг файл вътре в js

  2. Филтрирайте масива с помощта на оператора $in на етап $project

  3. Как да изпълня командата mongodump програмно от node.js?

  4. Намерете най-големия размер на документа в MongoDB

  5. ECONNREFUSED грешка при свързване към mongodb от node.js