MongoDB / CouchDB:将表加入自己

我有一个关系数据模型,我正考虑迁移到MongoDB或CouchDB,并试图了解这些查询如何工作。 假设我有两个实体Employees和Projects以及一个名为Assignments的多对多连接表。 我想查询两个用户协作的所有项目。 在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 = ?

假如我有Employee,Project和Assignment“文档”,我会如何在NoSQL中做到这一点? 或者,你会以不同的方式构建文档,这将如何影响查询?

我很乐意听到Mongo的查询API和Couch的map / reduce方法的答案。


我只能分享一下沙发的视野,在那里我每隔一段时间就放松一下。 首先,在处理基于文档的系统时,你几乎总是不得不故意忘记SQL。

其次,您可以选择更改结构并将实体数量降至最低,而不需要连接,也可以使用将不同类型的文档组合为单个结果集的视图。

前者(重新设计)是首选的方法,因为连接本质上是nosql的一种外国方法,因为规范化并不是必需的。 基于文档不是关系型的。


在MongoDB中,你可以这样做。 我使用交互式JavaScript Shell。

首先创建一些用户:

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

查找Joe或Moe工作的所有项目

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

查找Joe和moe工作的所有项目

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

要获得所有employess的特定项目,您需要两个查询。 寻找C项目的所有员工

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

在你的Appllication中,你从返回的值中构建一个新的查询并构建这个查询:

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

我希望这有助于理解MongoDB的工作方式以及如何建立关系。 我在这里使用了手动解引用。 这意味着我直接保存ObjectID并手动获取它。 还有“DBRef”,然后你的驱动程序会为你取回它。


你正在寻找的是一个N:M映射。 在这种情况下,您试图将表映射到自身,但这与尝试将“员工”映射到“项目”并无太大区别。

这里有一个很长的回答,我不会在这里重复。

在你的具体情况下,我认为你需要重新设计你的数据。 您有一个包含两个数据点的assignments表: projectIDemployeedID 。 这是将N个项目加入M员工的典型表格。

在MongoDB中,你通常根本没有这个“表”。 如果您想将员工分配到项目中,则可以在项目本身中存储一个employeeID数组。

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

看起来你的查询基本上是“找到员工2和3在一起工作的所有项目”。 MongoDB有一个$all查询操作符,可以为你提供上述结构。

请注意,这只是一个查询。 在进行模式设计时,查看整个系统并确定所有重要的查询非常重要。

链接地址: http://www.djcxy.com/p/15159.html

上一篇: MongoDB/CouchDB: Join a table to itself

下一篇: When to Redis? When to MongoDB?