使用Node.js + Express + MongoDB从多个集合中获取数据 -lookup-

首先, 或者 先说一下

我們希望從works中提取數據,並根據user_id還提取相應的users數據。但是,當我們一次提取多個數據並進行合併時,使用MongoDB相對於MySQL來說似乎更難處理。經過一番研究後,我們發現MongoDB也有類似MySQL中的左連接(left join)的用法。

数据

{
  "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'
    } 
    ]
  }
]

在获取工作数据的同时,还以用户信息的形式提取了userInfo。然而,userInfo中包含了用户对象数据的列表类型。
由于这样不方便使用,我们可以通过下一个$unwind操作,将对象从列表中提取出来。

从列表中提取

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那樣的方式,我覺得開發速度會加快。

相关

 

bannerAds