はじめに
下のデータのように、
works
からデータを取り出し、user_id
を基準してusers
のデータも一緒に取り出したい。
しかし、非同期処理によってデータを順番に取り出して結合するなど、
まとめてデータを取り出すとき、MongoDBはMySQLと比べて扱にくい感がある。
いろいろ調べたところ、mongoDBもMySQLのleft join
のような使い方があるようです。
Data
{
"user_name": "king",
"age": 20,
"id": "admin",
"pw": "1234",
"role": "admin",
"department": "A"
}
{
"title": "to be hero",
"due_date": "2022-12-15",
"create_datetime": "2022-12-03 19:59:39",
"user_id": "admin"
}
まずlookupで取り出してみる
db.collection("works").aggregate([
{
$lookup: {
from: "users",
localField: "user_id",
foreignField: "id",
as: "unserInfo"
},
},
]).toArray((err, result) => {
console.log(result)
res.render('./works/works.ejs', { works: result })
})
from
: 対象のコレクション
localField
: 結合に使われる基準のコレクションのフィールド (ここではworks
)
foreignField
: 結合に使われる対象のコレクションのフィールド(ここではusers
)
as
: 対象のコレクションのドキュメントの保存名
[
{
_id: new ObjectId("638b2c1b6c66bbaeee6c0aa6"),
title: 'to be hero',
due_date: '2022-12-15',
create_datetime: '2022-12-03 19:59:39',
user_id: 'admin',
unserInfo: [
{
_id: new ObjectId("6388ca58dbdf448d85e9e159"),
user_name: 'king',
age: 20,
id: 'admin',
pw: '1234',
role: 'admin',
department: 'A'
}
]
}
]
work
のデータに加えてusers
の情報をunserInfo
として取り出した。
しかし、unserInfo
の中にlist型としてusers
のobjectデータが入っている。
これだと使いにくいので、次の$unwind
でobjectをリストから取り出す。
リストからとりだす
db.collection("works").aggregate([
{
$lookup: {
from: "users",
localField: "user_id",
foreignField: "id",
as: "unserInfo"
},
},
//追加
{ $unwind: "$unserInfo" },
]).toArray((err, result) => {
res.render('./works/works.ejs', { works: result })
})
[
{
_id: new ObjectId("638b2c1b6c66bbaeee6c0aa6"),
title: 'to be hero',
due_date: '2022-12-15',
create_datetime: '2022-12-03 19:59:39',
user_id: 'admin',
unserInfo: {
_id: new ObjectId("6388ca58dbdf448d85e9e159"),
user_name: 'king',
age: 20,
id: 'admin',
pw: '1234',
role: 'admin',
department: 'A'
}
}
]
$unwind
を使うことでリストから取り出した。
もっと欲を言えば、オブジェクトからも取り出したい。
$project
をオブジェクトの中から取り出す。
必要なフィールドを結合する
db.collection("works").aggregate([
{
$lookup: {
from: "users",
localField: "user_id",
foreignField: "id",
as: "unserInfo"
},
},
{ $unwind: "$unserInfo" },
{
//追加
$project: {
_id: 1,
create_datetime: 1,
user_id: 1,
user_name: "$unserInfo.user_name",
role: "$unserInfo.role",
}
}
]).toArray((err, result) => {
res.render('./works/works.ejs', { works: result })
})
[
{
_id: new ObjectId("638b2c1b6c66bbaeee6c0aa6"),
create_datetime: '2022-12-03 19:59:39',
user_id: 'admin',
user_name: 'king',
role: 'admin'
}
]
基準となる元のフィールドは1
を指定することで表示することができる。
結合するデータは、その新・旧のフィールドを指定する必要がある。
しかし、指定なしですべてのフィールドを並べてくれる方法はまだないようです。
おわりに
残念ながらまだmysqlのような完璧なleft join
はない模様
sql文がそのまま使えないのが、mongoDBの欠点として感じる。
しかし、inner joinのような使い方ができるのであれば、開発スピードが増す気がする。
関連