mongodb的聚合查询 $lookup 多表关联查询 (let 多字段 pipeline )

  • 这两天做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)
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值