- 这两天做mongodb的多表且多字段关联查询,这里做下使用记录,后续可套用该模式使用。
- 如果不考虑性能影响的话,可以无限使用 lookup 做多表关联。
- 多表关联查询的效率比单表加循环查询效率非常高。
let mongoUrl=`mongodb://root:pwd@127.0.0.1:27017/dbName`;//数据库连接
let mongo=require("lycq").mongo;
async function main(){
console.log("启动")
let db=await mongo.newMongoClient(mongoUrl);
console.time();
await findTableName(db);//执行
console.timeEnd();
}
main();
async function findTableName(db){
let db_Address=db.collection("tableAddress");//保存索引的数据库
// [116.279943 #lng经度 40.049971, #lat纬度]
let geoNear={
$geoNear: {
// query:{unitName:{$regex:"海"}}, // 查询条件
near: { type: "Point", coordinates: [ 116 , 26 ] },//这里是设置中心点,用于计算主表与中心点的直线距离,
maxDistance:100*1000,//最远距离 1就是1米,这里设定100公里 减少查询的资源消耗
distanceField: "distance", //存放距离的参数
spherical: true, //是否采用球面几何计算
// num:100,// 返回数据个数(默认为100)
// distanceField:存放距离的参数
// maxDistance:最远距离
// query: 查询条件
// num: 返回数据个数(默认为100)
// spherical:是否采用球面几何计算
// near:从距离最近的点开始搜索
}
}
let lookupSK= {
$lookup:
{
from: "tableA", //从表
let: {
"unitCode": "$unitCode", //这里是将上一级的字段进行引入
"addressCode": "$addressCode",
"distance":"$distance",
},
"pipeline": [
{ $match:
{
//注意这里使用过滤条件的话会影响性能,应该是查询出的结果到下级操作进行过滤,而不是在这里进行过滤,否则效率影响很大。
// state:"0",
// missionTime:{$gt:Date.now()-(86400000*180)},
//查找对等的数据 $是当前关联的字段,$$是上以及的数据字段
//这里的$eq是让上下级对等的过滤条件,用$or 是未来让多个字段匹配
$expr: {$or: [ { $eq: ["$unitCode","$$unitCode" ] },{ $eq: ["$addressCode","$$addressCode" ] }]}
}
},
{$group:{_id:{unitCode:"$unitCode",addressCode:"$addressCode",distance:"$$distance",state:"$state",missionTime:"$missionTime"},skCount:{$sum:"$amount"}}},
{$project:{_id:0,distance:"$_id.distance",state:"$_id.state",missionTime:"$_id.missionTime",skCount:1}},
],
as: "sk" //为输出文档的新增值命名(值为关联的从表数据)
}
}
let project={$project:{
_id:0,unitCode:1,addressCode:1,distance:1,skCount:"$sk.skCount",
}};
let doc=await db_Address.aggregate([
geoNear, //先计算中心点与各个坐标点的直线距离,并且以设定的distance字段正序进行排序,该语句的执行必须添加2d索引,如果索引缺少数据或者不是数组[0,0]格式,则会报错。
lookupSK, //执行关联从表的关联查询,
{$match:{"sk":{$ne:[]}}}, //过滤无关联的数据
{$unwind: "$sk"}, //对从表的sk对象进行分组
{$match:{"sk.state":"0","sk.missionTime":{$gt:Date.now()-(86400000*180)}}},//这里进行过滤,效率比在从表的 pipeline 阶段进行过滤效率高很多,原本的过滤是接近3秒,这里只需要300多毫秒,
project, //进行字段结构重组
{$skip: 0}, // 跳过多少行
{$limit: 10}, //每页查询多少行
]).toArray();
for(let i=0;i<doc.length;i++){
console.log(i,JSON.stringify(doc[i]));
}
console.log("doc==",doc.length)
}