NodeJs操作MongoDB之多表查询($lookup)与常见问题

NodeJs操作MongoDB之多表查询($lookup)与常见问题

一,方法介绍

aggregate()方法来对数据进行聚合操作。aggregate()方法的语法如下

1 aggregate(operators,[options],callback)

operators参数是如表1所示的聚合运算符的数组,它允许你定义对数据执行什么汇总操作。options参数允许你设置readPreference属性,它定义了从哪里读取数据。callback参数是接受err和res

$lookup:可以做多表查询

1  {
2             $lookup://$lookup是如果涉及关联"_id",注意两个字段的类型,用string类型匹配ObjectId类型是没有结果的
3             {
4                 from: 'User',            // 右集合
5                 localField: 'UserId',    // 左集合 join 字段 数据类型得统一
6                 foreignField: '_id',         // 右集合 join 字段 数据类型得统一
7                 as: 'fromRole',           // 新生成字段(类型array)   
8             },
9         },

$match:通过使用query对象运算符来过滤文档集。

1 {$match:{"UserId:'5c429fe2c2462128fccc569b'}}

$unwind:unwind方法会将数组解开,每条包含数组中的一个值。

1 { $unwind: "$fromRole" },//数据打散

$lookup多表查询一起使用,$加$lookup as 的值(新生成字段)

$project:通过重命名,添加或删除字段重塑文档。你也可以重新计算值,并添加子文档。

1 //以下是包括title并排除name的例子:
2 {$project:{title:1,name:0}}
3 //以下是把name重命名为title的例子:
4 {$project{title:"$name"}}
5 //下面是添加一个新的total字段,并用price和tax字段计算它的值的例子:
6 {$project{total:{$add:["$price","$tax"]}}}

$limit:用来限制MongoDB聚合管道返回的文档数。

1 {$limit:5}//查询五条

$skip:指定处理聚合操作的下一个管道前跳过的一些文档。

和limit()以及skip()的写法也是一样的。

1 { $skip : 5 }//跳过五条 从0开始

$sort:将输入文档排序后输出。

排序指定一个带有field(需要排序的字段名):<sort_order>属性的对象,其中<sort_order>为1表示升序,而-1表示降序

$sort和我们find()中排序的写法也是一样的。

$group:将集合中的文档分组,可用于统计结果。

 把文档分成一组新的文档用于在管道中的下一级。新对象的字段必须在$group对象中定义。

  1. $addToSet 返回一组文档中所有文档所选字段的全部唯一值的数组。例如:colors:{$addToSet:"color"}
  2. $first 返回一组文档中一个字段的第一个值。例如:firstValue:{$first:"$value"}
  3. $last 返回一组文档中一个字段的最后一个值。例如:lastValue:{$last:"$value"}
  4. $max 返回一组文档中一个字段的最大值。例如:maxValue:{$max:"$value"}
  5. $min 返回一组文档中一个字段的最小值。例如:minValue:{$min:"$value"}
  6. $avg 返回一组文档中以个字段的平均值。例如:avgValue:{$avg:"$value"}
  7. $push 返回一组文档中所有文档所选字段的全部值的数组。例如:username:{$push:"$username"}
  8. $sum 返回一组文档中以个字段的全部值的总和。例如:total:{$sum:"$value"}

可用在聚合表达式的字符串和算术运算符

  1. $add:计算数值的总和。例如:valuePlus5:{$add:["$value",5]}
  2. $divide:给定两个数值,用第一个数除以第二个数。例如:valueDividedBy5:{$divide:["$value",5]}
  3. $mod:取模。例如:{$mod:["$value",5]}
  4. $multiply:计算数值数组的乘积。例如:{$multiply:["$value",5]}
  5. $subtract:给定两个数值,用第一个数减去第二个数。例如:{$subtract:["$value",5]}
  6. $concat:连接两个字符串 例如:{$concat:["str1","str2"]}
  7. $strcasecmp:比较两个字符串并返回一个整数来反应比较结果。例如 {$strcasecmp:["$value","$value"]}
  8. $substr:返回字符串的一部分。例如:hasTest:{$substr:["$value","test"]}
  9. $toLower:将字符串转化为小写。
  10. $toUpper:将字符串转化为大写

二,表结构与数据

2.1,用户集合(表)User

1,表结构

 1 "User": {
 2         "Code": "string",
 3         "Name": "string",
 4         "Email": "string",
 5         "Phone": "string",
 6         "Password": "string",
 7         "IsEnable": "bool",
 8         "LoginTime": "date",
 9         "CreateTime": "date",
10         "UpdateTime": "date"
11 },

2,插入的数据

 1 {
 2     "_id" : ObjectId("5c429fe2c2462128fccc569b"),
 3     "Code" : "1234567@qq.com",
 4     "Name" : "jackson影琪",
 5     "Email" : "123456@qq.com",
 6     "Phone" : "15454545454",
 7     "Password" : "5f4dcc3b5aa765d61d8327deb882cf99",
 8     "IsEnable" : true,
 9     "CreateTime" : ISODate("2019-01-19T03:56:18.966Z")
10 }

2.2,角色集合(表)Role

1,表结构

1  "Role": {
2         "Code": "string",
3         "Name": "string",
4         "Description": "string",
5         "CreateTime": "date"
6     },

2,插入的数据

 1 {
 2     "_id" : ObjectId("5c42cd8fa450b70a55efdf7e"),
 3     "Code" : "yingqiRole",
 4     "Name" : "yingqi角色",
 5     "Description" : "yingqi角色",
 6     "CreateTime" : ISODate("2019-01-19T03:56:18.966Z")
 7 },
 8 {
 9     "_id" : ObjectId("5c4564848e297d394920f380"),
10     "Code" : "adminRole",
11     "Name" : "管理员角色",
12     "Description" : "管理员角色",
13     "CreateTime" : ISODate("2019-01-21T03:56:18.966Z")
14 }

2.3,用户与角色关系集合(表)RoleToUser

1,表结构

1   "RoleToUser": {
2         "RoleId": "objectId",//角色表主键_id
3         "UserId": "objectId",//用户表主键_id
4         "CreateTime": "date"
5     }

2,插入的数据

 1 {
 2     "_id" : ObjectId("5c42cec9a450b70a55efe01a"),
 3     "RoleId" : ObjectId("5c42cd8fa450b70a55efdf7e"),
 4     "UserId" : ObjectId("5c429fe2c2462128fccc569b"),
 5     "CreateTime" : ISODate("2019-01-19T03:56:18.966Z")
 6 },
 7 {
 8     "_id" : ObjectId("5c4564508e297d394920f363"),
 9     "RoleId" : ObjectId("5c4564848e297d394920f380"),
10     "UserId" : ObjectId("5c429fe2c2462128fccc569b"),
11     "CreateTime" : ISODate("2019-01-21T03:56:18.966Z")
12 }

三,聚合查询与接口抛出

3.1,聚合查询方法封装

 1 /**
 2  * 聚合查询 查询多条数据 多表查询
 3  * @param table_name 表名
 4  * @param pipeLine 管道 [{$lookup: {
 5                         from:'表名',            // 右集合
 6                         localField: 'UserId',    // 左集合 join 字段 数据类型得统一
 7                         foreignField: '_id',         // 右集合 join 字段 数据类型得统一
 8                         as: 'fromUser',           // 新生成字段(类型array)   
 9                     }}
10                     ,{$match:{"_id:''}},
11                      { $unwind: "$fromUser" },//数据打散
12                 ]
13  * @param callback 回调方法
14  */
15 MongoDbAction.queryAggregateMultiTable = function (table_name, pipeLine, callback) {
16     var node_model = this.getConnection(table_name);
17     if (!node_model || node_model.message) {
18         if (callback) callback(1, node_model)
19     } else {
20         node_model.aggregate(pipeLine)
21             .exec(function (err, res) {
22                 if (err) {
23                     if (callback) callback(err);
24                 } else {
25                     if (callback) callback(null, res);
26                 }
27             });
28     }
29 };

3.2,连接查询并抛出接口

 1 //聚合查询数据 多表连接查询 根据用户id获取角色信息
 2 router.put('/user/getRoleInfoByUserId', function (req, res) {
 3     var tableName = req.body.tableName;//'User'
 4     var singleId = req.body.Code;
 5     let conditions = {
 6         UserId:mongoose.Types.ObjectId(singleId)
 7         //_id:{$type:3}
 8     }
 9     let data = {
10         httpCode: 200,
11         message: "查询成功!",
12         status: 1,
13         data: null,
14     }
15     let pipeLine = [
16         {
17             $lookup:
18             {
19                 from: 'User',            // 右集合
20                 localField: 'UserId',    // 左集合 join 字段 数据类型得统一
21                 foreignField: '_id',         // 右集合 join 字段 数据类型得统一
22                 as: 'fromUser',           // 新生成字段(类型array)   
23             },
24         },
25         {
26             $lookup:
27             {
28                 from: 'Role',            // 右集合
29                 localField: 'RoleId',    // 左集合 join 字段 数据类型得统一
30                 foreignField: '_id',         // 右集合 join 字段 数据类型得统一
31                 as: 'fromRole',           // 新生成字段(类型array)
32             }
33         },
34         { $match: conditions },
35         { $unwind: "$fromUser" },
36         { $unwind: "$fromRole" },//数据打散
37 ]
38     MongoDbAction.queryAggregateMultiTable(tableName, pipeLine, function (err, result) {
39         if (!err) {
40             data.data = result
41             res.status(data.httpCode).json(data);
42         } else {
43             data.status = 0
44             data.message = "未查询到数据!"
45             data.data = result
46             res.status(data.httpCode).json(data);
47         }
48     });
49 })

3.3,查询结果

查询的条件

查询的结果,已使用unwind方法会将数组解开

四,常见问题

1,$match是如果涉及到"_id",直接传入是没有结果返回的,这是坑1

解决思路:使用aggregate()方法的$match过滤,数据类型必须统一

解决办法:使用mongoose将字符串转成ObjectId,mongoose.Types.ObjectId()方法的使用如下:

1  let conditions = {
2         UserId:mongoose.Types.ObjectId(singleId)//aggregate的$match是如果涉及到"_id",注意字段的类型,如果数据库是ObjectId类型,直接传入是没有结果的,需要将传入的string类型转成ObjectId类型才有结果
3         //_id:{$type:3}
4     }

2,$lookup是如果涉及到"_id",两字段的类型不统一是没有结果返回的,这是坑2

注意两个字段的类型,用string类型匹配ObjectId类型是没有结果的 解决办法:建立集合时与插入数据时,注意类型统一
1  "_id" : ObjectId("5c42cec9a450b70a55efe01a"), "UserId" : ObjectId("5c429fe2c2462128fccc569b"),

 

原文地址:https://www.cnblogs.com/jackson-zhangjiang/p/10291767.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读552次。com.mongodb.MongoQueryException: Query failed with error code 292 and error message 'Executor error during find command :: caused by :: Sort exceeded memory limit of 104857600 bytes, but did not opt in to external sorting.' on server 11.51.141.63:27017 _mongodb 大文件 下载失败
文章浏览阅读635次,点赞9次,收藏8次。MongoDB 是一种 NoSQL 数据库,它将每个数据存储为一个文档,这里的文档类似于 JSON/BSON 对象,具体数据结构由键值(key/value)对组成。
文章浏览阅读2.1k次。和。_mongodb 日期类型
文章浏览阅读1.7k次。Scalestack等客户期待使用MongoDB Atlas Vector Search和Amazon Bedrock构建下一代应用程序
文章浏览阅读970次。SpringBoot整合中间件mongodb、ES_springboot3 elasticsearch json数据
文章浏览阅读673次。MongoDB 简介_尚医通sql
文章浏览阅读1k次,点赞8次,收藏9次。官网下载MongoDB安装包后进行解压(因了解并不深入,故暂不进行详细说明,自行查找其他安装方法,后期了解深入后将进行该教程的完善)在bin目录下使用命令启动:./mongod --config …/mongodb.conf。该文章任然处于完善中,如果存在错误遗漏的地方,欢迎私信联系。安装相关的nuget包后即可通过以下方法连接数据。YX9010_0@的第二十篇文章。
文章浏览阅读1.2k次,点赞17次,收藏26次。社交场景, 使用 MongoDB 存储存储用户信息, 以及用户发表的朋友圈信息, 通过地理位置索引实现附近的人, 地点等功能.游戏场景, 使用 MongoDB 存储游戏用户信息, 用户的装备, 积分等直接以内嵌文档的形式存储, 方便查询, 高效率存储和访问.物流场景, 使用 MongoDB 存储订单信息, 订单状态在运送过程中会不断更新, 以 MongoDB 内嵌数组的形式来存储, 一次查询就能将订单所有的变更读取出来.物联网场景, 使用 MongoDB 存储所有接入的智能设备信息, 以及设备汇报的日
文章浏览阅读686次。您可以使用 update_one() 方法来更新 MongoDB 中调用的记录或文档。update_one() 方法的第一个参数是 query 对象,用于定义要更新的文档。注释:如果查询找到多个记录,则仅更新第一个匹配项。第二个参数是定义文档新值的对象。_python 更新 mongodb 数据
文章浏览阅读1.3k次。首先来学习一下nosql这里安装就不进行介绍 只记录一下让自己了解mongodb。_nosql注入
文章浏览阅读4.1k次,点赞8次,收藏7次。在data的目录下,创建一个db文件。因为启动MongoDB服务之前必须创建数据库文件的存放文件夹,否则命令不会自动创建,而且不能启动成功。第一步:安装时,Custom是指可以自定义安装路径,然后傻瓜式安装即可(注意:先不要安装图形化工具,否则安装时间会特别长):如果要想连接成功,必须要开服务,即mongod -dbpath C:MongoDBdatadb的cmd要一直开着。然后回车,ctrl+F输入port找到端口号,一般为:27017。打开命令行,然后找到bin文件地址,并输入。_mongodb windows安装
文章浏览阅读5.1k次,点赞3次,收藏43次。详细介绍MongoDB数据库的基本知识,安装方法,基本操作,_mongodb数据库
文章浏览阅读3.2k次。安装教程翻看以往文章。_navicat 连接mongodb
文章浏览阅读426次,点赞9次,收藏12次。win10开放端口:https://blog.csdn.net/m0_43605481/article/details/119255256。我的是阿里云服务器,所以直接在安全组中加入规则,端口范围:27017,授权对象:0.0.0.0。windows在mongodb安装文件夹的bin文件夹中的mongod.cfg。数据库名字是test,打算创建一个用户,账号aaa,密码bbb,权限readWrite。因为该用户是创建在test数据库的,所以在最后要加上test。O了,然后恢复了test的数据。
文章浏览阅读1.1k次。聚合操作主要用于处理数据并返回计算结果。聚合操作将来自多个文档的值组合在一起,按条件分组后,再进行一系列操作(如求和、平均值、最大值、最小值)以返回单个结果。MongoDB的聚合查询​聚合是MongoDB的高级查询语言,它允许我们通过转化合并由多个文档的数据来生成新的在单个文档里不存在的文档信息。MongoDB中聚合(aggregate)主要用于处理数据(例如分组统计平均值、求和、最大值等),并返回计算后的数据结果,有点类似sql语句中的count(*)、groupby。..._如何将几个db的数据统整在一起做查询
文章浏览阅读680次,点赞7次,收藏8次。(2)application.properties配置文件。(4)UserService类。(5)测试和测试结果。
文章浏览阅读1k次,点赞17次,收藏25次。Studio 3T 2023.9 (macOS, Linux, Windows) - MongoDB 的专业 GUI、IDE 和 客户端,支持自然语言查询_mongodb客户端
文章浏览阅读1.1k次,点赞32次,收藏27次。插件式的存储引擎架构可以实现 Server 层和存储引擎层的解耦,可以支持多种存储引擎,如 MySQL 既可以支持 B-Tree 结构的 InnoDB 存储引擎,还可以支持 LSM 结构的 RocksDB 存储引擎。MongoDB 中的记录就是一个 BSON 文档,它是由键值对组成的数据结构,类似于 JSON 对象,是 MongoDB 中的基本数据单元。的简称,是 JSON 文档的二进制表示,支持将文档和数组嵌入到其他文档和数组中,还包含允许表示不属于 JSON 规范的数据类型的扩展。
文章浏览阅读5.1k次,点赞6次,收藏96次。本文设计了一种基于智能室内温度控制的自动调速风扇。以STM32系列单片机为核心主控板,通过程序代码驱动和使用温度传感器模块实现对环境温度的实时监测,并可以实时显示环境温度。同时,可以设置温度检测的上下警告值,根据需求自行调节。_stm32 温控风扇
文章浏览阅读898次,点赞13次,收藏21次。在MongoDB中,我们使用find()和find_one()方法来在集合中查找数据,就像在MySQL数据库中使用SELECT语句来在表中查找数据一样。_pymongo find_one