MongoDB(30) - 集計処理(aggregate)⑪複数コレクションの結合

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

サンプルデータ

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

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

複数コレクションの結合

1つのコレクションから複数のコレクションを同時に結合します。

コレクションの結合方法は下記の通りです。

  • 従業員コレクション(employee)と課コレクション(division)を結合
    結合キーは課ID(k_id)
  • 従業員コレクション(employeeと役職コレクション(position)を結合
    結合キーは役職ID(p_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: "position",
localField: "p_id",
foreignField: "p_id",
as: "position_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" : "総務課" } ], "position_docs" : [ { "_id" : ObjectId("612f07d768110fe533ed9d1d"), "p_id" : "po1", "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" : "企画課" } ], "position_docs" : [ { "_id" : ObjectId("612f07d768110fe533ed9d1e"), "p_id" : "po2", "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課" } ], "position_docs" : [ { "_id" : ObjectId("612f07d768110fe533ed9d1f"), "p_id" : "po3", "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課" } ], "position_docs" : [ { "_id" : ObjectId("612f07d768110fe533ed9d20"), "p_id" : "po4", "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課" } ], "position_docs" : [ { "_id" : ObjectId("612f07d768110fe533ed9d20"), "p_id" : "po4", "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課" } ], "position_docs" : [ { "_id" : ObjectId("612f07d768110fe533ed9d20"), "p_id" : "po4", "name" : "一般社員" } ] }

従業員コレクションから、課コレクションと役職コレクションを結合することができました。

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

複数コレクションの結合を行った結果に対して、$projectを使って表示フィールドを絞り込みます。

オブジェクトID(_id)を非表示にし、従業員ID(e_id)・従業員名・課の名称・役職名を表示します。

また同時に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: "position",
localField: "p_id",
foreignField: "p_id",
as: "position_docs"
}},
{$project:{
"_id": 0,
"e_id": 1,
"name": 1,
"division_docs.name": 1,
"position_docs.name": 1
}},
{$unwind: "$division_docs"}, // 課コレクションの展開
{$unwind: "$position_docs"} // 役職コレクションの展開
])
{ "e_id" : "emp001", "name" : "高山", "division_docs" : { "name" : "総務課" }, "position_docs" : { "name" : "社長" } }
{ "e_id" : "emp002", "name" : "生駒", "division_docs" : { "name" : "企画課" }, "position_docs" : { "name" : "部長" } }
{ "e_id" : "emp003", "name" : "嘉喜", "division_docs" : { "name" : "開発1課" }, "position_docs" : { "name" : "課長" } }
{ "e_id" : "emp004", "name" : "与田", "division_docs" : { "name" : "開発2課" }, "position_docs" : { "name" : "一般社員" } }
{ "e_id" : "emp005", "name" : "松田", "division_docs" : { "name" : "開発1課" }, "position_docs" : { "name" : "一般社員" } }
{ "e_id" : "emp006", "name" : "菅井", "division_docs" : { "name" : "開発2課" }, "position_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': 'position',
'localField': 'p_id',
'foreignField': 'p_id',
'as': 'position_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': 'position',
'localField': 'p_id',
'foreignField': 'p_id',
'as': 'position_docs'
}},
{'$project':{
'_id': 0,
'e_id': 1,
'name': 1,
'division_docs.name': 1,
'position_docs.name': 1
}},
{'$unwind': '$division_docs'}, # 課コレクションの展開
{'$unwind': '$position_docs'} # 役職コレクションの展開
])
for doc in docs:
print(doc)

次回は、集計結果のソート/表示件数制限/取得開始位置の指定を行います。