私はMongoDBの理論と、結合をサポートしていないという事実を知っており、埋め込みドキュメントを使用するか、可能な限り非正規化する必要がありますが、ここにあります:
次のような複数のドキュメントがあります。
例:
Users:
{ _id: 1, first_name: 'Bill', last_name: 'Gates', suburb: 1 }
{ _id: 2, first_name: 'Steve', last_name: 'Jobs', suburb: 3 }
Suburb:
{ _id: 1, name: 'Suburb A', state: 1 }
{ _id: 2, name: 'Suburb B', state: 1 }
{ _id: 3, name: 'Suburb C', state: 3 }
State:
{ _id: 1, name: 'LA' }
{ _id: 3, name: 'NY' }
Child:
{ _id: 1, _user_id: 1, first_name: 'Little Billy', last_name: 'Gates' }
{ _id: 2, _user_id: 2, first_name: 'Little Stevie', last_name: 'Jobs' }
実装する必要がある検索は次のとおりです。
私はそれを達成するために複数のクエリを実行する必要があることを知っていますが、どのようにそれを達成できますか? mapReduceまたは集計で?
解決策を教えてください。
MapReduceを使おうとしましたが、state_idを含むユーザーからのドキュメントを取得できなかったので、ここで取り上げました。
この答えは時代遅れです。バージョン3.2以降、MongoDBは $ lookup 集計演算子を使用した左外部結合のサポートを制限しています
MongoDBは、複数のコレクション(期間)にまたがるクエリを実行しません。複数のコレクションのデータを結合する必要がある場合は、複数のクエリを実行して、アプリケーションレベルでデータを結合する必要があります。
これを行う必要があるのは、通常よりもむしろ例外であるべきです。そのようなJOINを頻繁にエミュレートする必要がある場合は、データベーススキーマを設計するときにまだリレーショナルすぎると考えているか、またはデータがMongoDBのドキュメントベースのストレージ概念に適していないことを意味します。
スキーマ設計に非正規化アプローチを採用すると、MongoDBが理解しやすくなります。つまり、要求元のクライアントアプリケーションがドキュメントを理解する方法でドキュメントを構造化します。基本的に、ドキュメントを ドメインオブジェクト としてモデル化し、アプリケーションで処理します。この方法でデータをモデル化すると、結合はそれほど重要ではなくなります。データを単一のコレクションに非正規化した方法を検討してください。
{
_id: 1,
first_name: 'Bill',
last_name: 'Gates',
suburb: 'Suburb A',
state: 'LA',
child : [ 3 ]
}
{
_id: 2,
first_name: 'Steve',
last_name: 'Jobs',
suburb: 'Suburb C',
state 'NY',
child: [ 4 ]
}
{
_id: 3,
first_name: 'Little Billy',
last_name: 'Gates',
suburb: 'Suburb A',
state: 'LA',
parent : [ 1 ]
}
{
_id: 4,
first_name: 'Little Stevie',
last_name: 'Jobs'
suburb: 'Suburb C',
state 'NY',
parent: [ 2 ]
}
最初の利点は、このスキーマの照会がはるかに簡単であることです。さらに、アドレスフィールドの更新は、フィールドが単一のドキュメントに埋め込まれているため、個々のPersonエンティティと一致するようになりました。親と子の間の双方向の関係にも注目してください。これにより、このコレクションは単なる個人のコレクションではありません。親子関係は、このコレクションも ソーシャルグラフ であることを意味します。 MongoDBのスキーマ設計 について考えるときに役立つ可能性のあるリソースを次に示します。
指定した条件に一致するすべてのレコードの配列を返し、現在のデータベースのすべてのコレクションを検索するJavaScript関数を次に示します。
function searchAll(query,fields,sort) {
var all = db.getCollectionNames();
var results = [];
for (var i in all) {
var coll = all[i];
if (coll == "system.indexes") continue;
db[coll].find(query,fields).sort(sort).forEach(
function (rec) {results.Push(rec);} );
}
return results;
}
Mongo Shellから、関数をコピーして貼り付け、次のように呼び出すことができます。
> var recs = searchAll({filename:{$ regex: '。pdf $'}}、{moddate:1、filename:1、_id:0}、{filename:1})> recs
そのため、mongodbで結合が可能になり、 $lookup
および $facet
ここでの集約は、おそらく複数のコレクションで見つけるための最良の方法です
db.collection.aggregate([
{ "$limit": 1 },
{ "$facet": {
"c1": [
{ "$lookup": {
"from": Users.collection.name,
"pipeline": [
{ "$match": { "first_name": "your_search_data" } }
],
"as": "collection1"
}}
],
"c2": [
{ "$lookup": {
"from": State.collection.name,
"pipeline": [
{ "$match": { "name": "your_search_data" } }
],
"as": "collection2"
}}
],
"c3": [
{ "$lookup": {
"from": State.collection.name,
"pipeline": [
{ "$match": { "name": "your_search_data" } }
],
"as": "collection3"
}}
]
}},
{ "$project": {
"data": {
"$concatArrays": [ "$c1", "$c2", "$c3" ]
}
}},
{ "$unwind": "$data" },
{ "$replaceRoot": { "newRoot": "$data" } }
])
@ brian-moquinなどに基づいて、単純なキーワードでキー(フィールド)全体でコレクション全体を検索する一連の関数を作成しました。
それは私の要点です。 https://Gist.github.com/fkiller/005dc8a07eaa3321110b3e5753dda71b
詳細については、最初にすべてのキーを収集する関数を作成しました。
_function keys(collectionName) {
mr = db.runCommand({
'mapreduce': collectionName,
'map': function () {
for (var key in this) { emit(key, null); }
},
'reduce': function (key, stuff) { return null; },
'out': 'my_collection' + '_keys'
});
return db[mr.result].distinct('_id');
}
_
次に、キー配列から_$or
_クエリを生成します。
_function createOR(fieldNames, keyword) {
var query = [];
fieldNames.forEach(function (item) {
var temp = {};
temp[item] = { $regex: '.*' + keyword + '.*' };
query.Push(temp);
});
if (query.length == 0) return false;
return { $or: query };
}
_
以下は、単一のコレクションを検索する関数です。
_function findany(collection, keyword) {
var query = createOR(keys(collection.getName()));
if (query) {
return collection.findOne(query, keyword);
} else {
return false;
}
}
_
そして、最後にすべてのコレクションの検索機能。
_function searchAll(keyword) {
var all = db.getCollectionNames();
var results = [];
all.forEach(function (collectionName) {
print(collectionName);
if (db[collectionName]) results.Push(findany(db[collectionName], keyword));
});
return results;
}
_
Mongoコンソールですべての関数をロードし、searchAll('any keyword')
を実行するだけです。