MongoDB(28) - 集計処理(aggregate)⑨コレクション結合・オブジェクト型と文字列型に展開

今回は、結合したコレクションをオブジェクト型と文字列型に展開します。

サンプルデータ

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

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

オブジェクト型に変換

前回のコレクション結合では、結合先コレクションのdivision_docsが [{}] というように配列の中にオブジェクトが入っている構造になっています。

$unwindを使うと、配列の中の値を展開することができます。

[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"
}},
{$project:{
"_id":0,
"name":1,
"division_docs.name":1
}},
{$unwind:"$division_docs"}
])
{ "name" : "高山", "division_docs" : { "name" : "総務課" } }
{ "name" : "生駒", "division_docs" : { "name" : "企画課" } }
{ "name" : "嘉喜", "division_docs" : { "name" : "開発1課" } }
{ "name" : "与田", "division_docs" : { "name" : "開発2課" } }
{ "name" : "松田", "division_docs" : { "name" : "開発1課" } }
{ "name" : "菅井", "division_docs" : { "name" : "開発2課" } }

division_docsの[]がとれて、{}というオブジェクト型になりました。

文字列型に変換

次にオブジェクト型を文字列型に変換します。

オブジェクト型に変換したデータに対して$groupを使い_id(集計キー)にe_id(従業員ID)を指定します。

e_idはユニークなので集計されません。

さらに表示したいフィールドに何らかの集計関数(maxなど)を使って、オブジェクト型から文字列型に変換します。

[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
> db.employee.aggregate([
{$lookup:{
from: "division",
localField:"k_id",
foreignField:"k_id",
as: "division_docs"
}},
{$project:{
"_id":0,
"e_id":1,
"name":1,
"division_docs.name":1
}},
{$unwind:"$division_docs"},
{$group:{
_id:"$e_id",
employeeName:{$max:"$name"},
divisionName:{$max:"$division_docs.name"}
}}
])
{ "_id" : "emp002", "employeeName" : "生駒", "divisionName" : "企画課" }
{ "_id" : "emp001", "employeeName" : "高山", "divisionName" : "総務課" }
{ "_id" : "emp004", "employeeName" : "与田", "divisionName" : "開発2課" }
{ "_id" : "emp006", "employeeName" : "菅井", "divisionName" : "開発2課" }
{ "_id" : "emp005", "employeeName" : "松田", "divisionName" : "開発1課" }
{ "_id" : "emp003", "employeeName" : "嘉喜", "divisionName" : "開発1課" }

結合した課コレクションの課の名称(division_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
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'
}},
{'$project':{
'_id':0,
'name':1,
'division_docs.name':1
}},
{'$unwind':'$division_docs'}
])
for doc in docs:
print(doc)

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

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