MongoDB(29) - 集計処理(aggregate)⑩コレクションの二重結合

今回は、コレクションの二重結合を行います。

サンプルデータ

以前用意した会社の部、課、従業員データを使用します。

集計処理(aggregate)①データ準備 - https://ailog.site/2021/09/02/2021/0902/

コレクションの二重結合

これまでは$lookupを使い2つのコレクションを結合してきました。

$lookupは1度に複数指定することができ、3つ以上のコレクションを結合することも可能です。

次のように3つのコレクションを結合してみます。

  • 従業員コレクション(employee)と課コレクション(division)を結合
    結合キーは課ID(k_id)
  • 課コレクション(division)と部署コレクション(department)を結合
    結合キーは部ID(b_id)

[Mongoシェル]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
> db.employee.aggregate([
{$lookup:{
from: "division",
localField: "k_id",
foreignField: "k_id",
as: "division_docs"
}},
{$lookup:{
from: "department",
localField: "division_docs.b_id",
foreignField: "b_id",
as: "department_docs"
}}
])
{ "_id" : ObjectId("612f07f568110fe533ed9d21"), "e_id" : "emp001", "k_id" : "ka1", "p_id" : "po1", "name" : "高山", "age" : 31, "salary" : 400000, "division_docs" : [ { "_id" : ObjectId("612f07b568110fe533ed9d19"), "k_id" : "ka1", "b_id" : "bu1", "name" : "総務課" } ], "department_docs" : [ { "_id" : ObjectId("612f075468110fe533ed9d16"), "b_id" : "bu1", "name" : "総務部" } ] }
{ "_id" : ObjectId("612f07f568110fe533ed9d22"), "e_id" : "emp002", "k_id" : "ka2", "p_id" : "po2", "name" : "生駒", "age" : 37, "salary" : 250000, "division_docs" : [ { "_id" : ObjectId("612f07b568110fe533ed9d1a"), "k_id" : "ka2", "b_id" : "bu2", "name" : "企画課" } ], "department_docs" : [ { "_id" : ObjectId("612f075468110fe533ed9d17"), "b_id" : "bu2", "name" : "企画部" } ] }
{ "_id" : ObjectId("612f07f568110fe533ed9d23"), "e_id" : "emp003", "k_id" : "ka3", "p_id" : "po3", "name" : "嘉喜", "age" : 23, "salary" : 200000, "division_docs" : [ { "_id" : ObjectId("612f07b568110fe533ed9d1b"), "k_id" : "ka3", "b_id" : "bu3", "name" : "開発1課" } ], "department_docs" : [ { "_id" : ObjectId("612f075468110fe533ed9d18"), "b_id" : "bu3", "name" : "開発部" } ] }
{ "_id" : ObjectId("612f07f568110fe533ed9d24"), "e_id" : "emp004", "k_id" : "ka4", "p_id" : "po4", "name" : "与田", "age" : 33, "salary" : 100000, "division_docs" : [ { "_id" : ObjectId("612f07b568110fe533ed9d1c"), "k_id" : "ka4", "b_id" : "bu3", "name" : "開発2課" } ], "department_docs" : [ { "_id" : ObjectId("612f075468110fe533ed9d18"), "b_id" : "bu3", "name" : "開発部" } ] }
{ "_id" : ObjectId("612f07f568110fe533ed9d25"), "e_id" : "emp005", "k_id" : "ka3", "p_id" : "po4", "name" : "松田", "age" : 35, "salary" : 550000, "division_docs" : [ { "_id" : ObjectId("612f07b568110fe533ed9d1b"), "k_id" : "ka3", "b_id" : "bu3", "name" : "開発1課" } ], "department_docs" : [ { "_id" : ObjectId("612f075468110fe533ed9d18"), "b_id" : "bu3", "name" : "開発部" } ] }
{ "_id" : ObjectId("612f07f568110fe533ed9d26"), "e_id" : "emp006", "k_id" : "ka4", "p_id" : "po4", "name" : "菅井", "age" : 45, "salary" : 120000, "division_docs" : [ { "_id" : ObjectId("612f07b568110fe533ed9d1c"), "k_id" : "ka4", "b_id" : "bu3", "name" : "開発2課" } ], "department_docs" : [ { "_id" : ObjectId("612f075468110fe533ed9d18"), "b_id" : "bu3", "name" : "開発部" } ] }

3つのコレクションを結合してデータを取得することができました。

表示フィールドの絞り込み

コレクションを二重結合して取得したドキュメントに対して、$projectを使って表示フィールドを絞り込みます。

また同時にunwindを使い、配列をオブジェクト型に展開します。

[Mongoシェル]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
> db.employee.aggregate([
{$lookup:{
from: "division",
localField: "k_id",
foreignField: "k_id",
as: "division_docs"
}},
{$lookup:{
from: "department",
localField: "division_docs.b_id",
foreignField: "b_id",
as: "department_docs"
}},
{$project: {
"_id":0,
"e_id":1,
"name":1,
"department_docs.name": 1,
"division_docs.name": 1
}},
{$unwind: "$department_docs"}, // 部署コレクションの展開
{$unwind: "$division_docs"} // 課コレクションの展開
])
{ "e_id" : "emp001", "name" : "高山", "division_docs" : { "name" : "総務課" }, "department_docs" : { "name" : "総務部" } }
{ "e_id" : "emp002", "name" : "生駒", "division_docs" : { "name" : "企画課" }, "department_docs" : { "name" : "企画部" } }
{ "e_id" : "emp003", "name" : "嘉喜", "division_docs" : { "name" : "開発1課" }, "department_docs" : { "name" : "開発部" } }
{ "e_id" : "emp004", "name" : "与田", "division_docs" : { "name" : "開発2課" }, "department_docs" : { "name" : "開発部" } }
{ "e_id" : "emp005", "name" : "松田", "division_docs" : { "name" : "開発1課" }, "department_docs" : { "name" : "開発部" } }
{ "e_id" : "emp006", "name" : "菅井", "division_docs" : { "name" : "開発2課" }, "department_docs" : { "name" : "開発部" } }

すっきりとした表示結果にすることができました。

Pythonで操作

上記の集計処理をPythonで行うと、次のようになります。

[ソースコード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import pymongo
from pymongo import MongoClient

# MongoDB操作用のインスタンスを作成
client = MongoClient() # [IPとポートを指定する場合] MongoClient('10.200.243.203', 27017')

# データベースの取得
db1 = client.db1

# コレクションの結合(オブジェクト型に展開)
docs = db1.employee.aggregate([
{'$lookup':{
'from': 'division',
'localField': 'k_id',
'foreignField': 'k_id',
'as': 'division_docs'
}},
{'$lookup':{
'from': 'department',
'localField': 'division_docs.b_id',
'foreignField': 'b_id',
'as': 'department_docs'
}}
])
for doc in docs:
print(doc)

# コレクションの結合(文字列型に展開)
docs = db1.employee.aggregate([
{'$lookup':{
'from': 'division',
'localField': 'k_id',
'foreignField': 'k_id',
'as': 'division_docs'
}},
{'$lookup':{
'from': 'department',
'localField': 'division_docs.b_id',
'foreignField': 'b_id',
'as': 'department_docs'
}},
{'$project': {
'_id':0,
'e_id':1,
'name':1,
'department_docs.name': 1,
'division_docs.name': 1
}},
{'$unwind': '$department_docs'},
{'$unwind': '$division_docs'}
])
for doc in docs:
print(doc)

次回は、複数コレクションの結合を行います。