2011-05-29 8 views
2

私はリレーショナルデータモデルを持っていますMongoDBやCouchDBに移行することを考えていますが、クエリの仕組みを理解しようとしています。 EmployeesとProjectsという2つのエンティティと、Assignmentsという多対多の結合テーブルがあるとします。私は、2人のユーザーが協力しているすべてのプロジェクトを照会したいと思います。MongoDB/CouchDB:自分自身にテーブルを結合する

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の中でこれを行うだろうか

:SQLで私はこのような何かをするだろうか?あるいは、ドキュメントの構造を変えて、クエリにどのような影響を与えるでしょうか?

私は、MongoのクエリAPIとCouchのmap/reduceアプローチの両方の答えを聞いてうれしいです。

答えて

3

私は、たまに、たまにリラックスして、ソファからの風景を共有することができます。まず、ドキュメントベースのシステムを扱う際には、ほとんどの場合、SQLを意図的に忘れる必要があります。

第2に、構造を変更し、結合を必要としないエンティティの量を最小限に減らすか、または異なるタイプのドキュメントを1つの結果セットに結合するビューを使用することができます。

正規化は必須条件ではないため、結合は基本的にnosqlの外部アプローチです。前者(再設計)が好ましい方法です。ドキュメントベースはリレーショナルではありません。

+0

ご回答ありがとうございます。しかし、私はこの種の構造を問い合わせることができるドキュメントモデルを見つけ出すのに苦労しています。何か案は? –

+0

私は主なエンティティを選択する必要があると思いますが、私はあなたのアプリケーションについて何も知らないので、私はそれを手伝うことはできません。システムをユーザの周りに集中させ、プロジェクトを比較的シンプルにしたり、ユーザのプロジェクトをラップしたり、その逆もあります。ユーザーとプロジェクトが同じように重要な場合は、ユーザーのデータの一部をプロジェクト/割り当てドキュメントに含めて、結合サンプルをフェッチするだけで十分です(2つのドキュメントを変更する必要があるという欠点があります)。最後に、ユーザーIDをプロジェクトに含めることができます。これは結合になります。 –

+0

PSの割り当ては、アプリケーションによっては、ユーザーまたはプロジェクトにマージする必要があります。 –

2

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" } 
はジョーと萌えはあなたが2つのクエリを必要とする特定のプロジェクトのためのすべてのemployessを取得するには

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

を働く上ですべてのプロジェクトを検索ジョーOR萌え

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

を働く上ですべてのプロジェクトを検索します。私はMongoDBの仕組みを理解するのに役立っていることを期待

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

と:あなたが戻っ値と ビルドこのクエリから新しいクエリを作成し、あなたのAppllicationで プロジェクトC.からすべての従業員

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

を検索どのように関係を構築することができます。ここではマニュアル逆参照を使用しました。つまり、ObjectIDを直接保存し、手動で取得します。また、 "DBRef"が存在し、ドライバがそれを取得します。

+0

プロジェクトクエリーで従業員を「参加」する方法があるので、最後の2つのクエリーを1つにまとめることができますか? – FrederickCook

+0

いいえ、MongoDBには「結合」はありません。これは「機能」です。あなたはクライアント上でそれを行う必要があります。あなたのソフトウェアで。 –

+0

すばらしいコメントSid、本当に便利です –

0

あなたが探しているのは事実上N:Mマッピングです。この場合、自分自身にテーブルをマップしようとしていますが、これは「従業員」を「プロジェクト」にマップしようとすることとあまり変わりありません。

私はここで繰り返しませんので、長い答えがover hereです。

具体的には、データを少し再設計する必要があると思います。 assignmentsテーブルには、projectIDemployeedIDの2つのデータポイントが含まれています。これはN個のプロジェクトをM社の従業員に参加させるための古典的なテーブルです。

MongoDBでは、通常この「テーブル」はありません。従業員をプロジェクトに割り当てる場合は、employeeIDの配列をプロジェクト自体に保存するだけです。

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

あなたのクエリは基本的に「従業員2と3が一緒に作業しているすべてのプロジェクトを見つける」であるように見えます。 MongoDBには上記の構造でこれを行う$all query operatorがあります。

これは1つのクエリに過ぎません。スキーマ設計を行う際には、システム全体を見て、すべてのという重要なクエリを識別することが重要です。

関連する問題