MongoDB / CouchDB: присоединить таблицу к себе - PullRequest
2 голосов
/ 30 мая 2011

У меня есть реляционная модель данных, которую я думаю о переходе на MongoDB или CouchDB, и пытаюсь понять, как будут работать запросы. Предположим, у меня есть две сущности, Сотрудники и Проекты, и таблица соединений «многие ко многим», называемая Назначениями. Я хочу запросить все проекты, над которыми сотрудничали два пользователя. В SQL я мог бы сделать что-то вроде этого:

SELECT DISTINCT a1.project_id
FROM assignments a1, assignments a2
WHERE a1.project_id = a2.project_id
AND a1.employee_id = ?
AND a2.employee_id = ?

Как бы я сделал это в NoSQL, если у меня есть «документы» Employee, Project и Assignment? Или вы по-другому структурируете документы, и как это повлияет на запрос?

Я был бы рад услышать ответы как по API запросов Монго, так и по подходу Couch для карт / сокращения.

Ответы [ 3 ]

3 голосов
/ 30 мая 2011

Я могу только поделиться видом с дивана, где я иногда отдыхаю.Во-первых, вам почти всегда нужно преднамеренно забывать SQL при работе с системами на основе документов.

Во-вторых, у вас будет возможность либо изменить структуру, либо сократить количество сущностей до минимума, который не потребуетобъединяет, или вы можете использовать представления, которые будут объединять документы разных типов в один набор результатов.

Первый (редизайн) является предпочтительным методом, так как соединения по сути являются сторонним подходом для nosql, поскольку нормализация там не является обязательным требованием.Основанный на документе не реляционный.

2 голосов
/ 30 мая 2011

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

Сначала создайте несколько пользователей:

> db.so.employee.insert({name: "Joe"})
> db.so.employee.insert({name: "Moe"})
> db.so.employee.insert({name: "Bart"})
> db.so.employee.insert({name: "Homer"})
> db.so.employee.find()
{ "_id" : ObjectId("4de35ccbcc0379536e1ac43b"), "name" : "Joe" }
{ "_id" : ObjectId("4de35ccfcc0379536e1ac43c"), "name" : "Moe" }
{ "_id" : ObjectId("4de35cd3cc0379536e1ac43d"), "name" : "Bart" }
{ "_id" : ObjectId("4de35cd7cc0379536e1ac43e"), "name" : "Homer" }

Теперь создайте несколько проектов

> db.so.project.insert({name: "Web App A"})
> db.so.project.insert({name: "Web App B"})
> db.so.project.insert({name: "Web App C"})
> db.so.project.find();
{ "_id" : ObjectId("4de35d0fcc0379536e1ac43f"), "name" : "Web App A" }
{ "_id" : ObjectId("4de35d13cc0379536e1ac440"), "name" : "Web App B" }
{ "_id" : ObjectId("4de35d15cc0379536e1ac441"), "name" : "Web App C" }

Добавление пользователей в проекты

> db.so.project.update({name: "Web App A"}, {$push: {employees: ObjectId('4de35ccbcc0379536e1ac43b') }})
> db.so.project.update({name: "Web App A"}, {$push: {employees: ObjectId('4de35ccfcc0379536e1ac43c') }})
> db.so.project.update({name: "Web App B"}, {$push: {employees: ObjectId('4de35ccfcc0379536e1ac43c') }})
> db.so.project.update({name: "Web App C"}, {$push: {employees: ObjectId('4de35ccfcc0379536e1ac43c') }})
> db.so.project.update({name: "Web App B"}, {$push: {employees: ObjectId('4de35cd3cc0379536e1ac43d') }})
> db.so.project.update({name: "Web App C"}, {$push: {employees: ObjectId('4de35cd3cc0379536e1ac43d') }})
> db.so.project.update({name: "Web App B"}, {$push: {employees: ObjectId('4de35cd7cc0379536e1ac43e') }})

> db.so.project.find()
{ "_id" : ObjectId("4de35d0fcc0379536e1ac43f"), "employees" : [
    ObjectId("4de35ccbcc0379536e1ac43b"),
    ObjectId("4de35ccfcc0379536e1ac43c")
], "name" : "Web App A" }
{ "_id" : ObjectId("4de35d15cc0379536e1ac441"), "employees" : [
    ObjectId("4de35ccfcc0379536e1ac43c"),
    ObjectId("4de35cd3cc0379536e1ac43d")
], "name" : "Web App C" }
{ "_id" : ObjectId("4de35d13cc0379536e1ac440"), "employees" : [
    ObjectId("4de35cd3cc0379536e1ac43d"),
    ObjectId("4de35cd7cc0379536e1ac43e")
], "name" : "Web App B" }

Если вы сейчас хотите найти все проекты, над которыми работает «Джо»

> db.so.project.find({employees: ObjectId('4de35ccbcc0379536e1ac43b') }, {name: 1})
{ "_id" : ObjectId("4de35d0fcc0379536e1ac43f"), "name" : "Web App A" }

Найти все проекты, над которыми работает Джо или Мо.

> db.so.project.find({employees: {$in: [ObjectId('4de35ccbcc0379536e1ac43b'), ObjectId('4de35ccfcc0379536e1ac43c')] }}, {name: 1})
{ "_id" : ObjectId("4de35d0fcc0379536e1ac43f"), "name" : "Web App A" }
{ "_id" : ObjectId("4de35d15cc0379536e1ac441"), "name" : "Web App C" }
{ "_id" : ObjectId("4de35d13cc0379536e1ac440"), "name" : "Web App B" }

Найти все проекты, над которыми работает Джо и Мо

> db.so.project.find({employees: {$all: [ObjectId('4de35ccbcc0379536e1ac43b'), ObjectId('4de35ccfcc0379536e1ac43c')] }}, {name: 1})
{ "_id" : ObjectId("4de35d0fcc0379536e1ac43f"), "name" : "Web App A" }

Чтобы получить все рабочие места для конкретного проекта, вам нужно два запроса. обнаружение все сотрудники проекта С.

> db.so.project.find({name: "Web App C"}, {employees: 1})
{ "_id" : ObjectId("4de35d15cc0379536e1ac441"), "employees" : [
    ObjectId("4de35ccfcc0379536e1ac43c"),
    ObjectId("4de35cd3cc0379536e1ac43d")
] }

В вашей заявке вы строите новый запрос из возвращаемых значений и построить этот запрос:

> db.so.employee.find({_id: {$in: [ObjectId('4de35ccfcc0379536e1ac43c'), ObjectId('4de35cd3cc0379536e1ac43d')] }})
{ "_id" : ObjectId("4de35ccfcc0379536e1ac43c"), "name" : "Moe" }
{ "_id" : ObjectId("4de35cd3cc0379536e1ac43d"), "name" : "Bart" }

Я надеялся, что это помогло понять, как работает MongoDB и как вы можете строить отношения. Я использовал разыменование вручную здесь. Это означает, что я сохраняю ObjectID напрямую и получаю его вручную. Также существует «DBRef», и ваш Драйвер затем извлекает его для вас.

0 голосов
/ 30 мая 2011

То, что вы ищете, по сути является N: M отображениемВ этом случае вы пытаетесь сопоставить таблицу с самим собой, но это не очень отличается от попытки сопоставить «Сотрудники» с «Проектами».

Здесь есть длинный ответ здесь на ТАК, что я не буду здесь повторяться.

В вашем конкретном случае, я думаю, вам нужно немного изменить дизайн ваших данных.У вас есть таблица assignments, содержащая две точки данных: projectID и employeedID.Это классическая таблица для объединения N проектов с сотрудниками M.

В MongoDB у вас вообще нет этой "таблицы" вообще.Если вы хотите назначить сотрудников для проекта, вы можете просто сохранить массив employeeID в самом проекте.

{ name: 'projectx', emps: [ 1, 2, 3] }
{ name: 'projecty', emps: [ 3, 2] }

Похоже, ваш запрос в основном "найти все проекты, где сотрудник2 и 3 работают вместе ".MongoDB имеет $all оператор запроса , который сделает это за вас с вышеуказанной структурой.

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

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