首页 > 解决方案 > MongoDB 将 sql 转换为 mongo 查询(使用 id-1 加入)

问题描述

我想更改以下 sql 查询:

select a1.opis_ruchu as poprzednik, a2.opis_ruchu as nastepnik,
count(a1.opis_ruchu) as ilosc_wystapien
from public.informacje a1 join public.informacje a2
on a1.id = a2.id-1
group by a1.opis_ruchu, a2.opis_ruchu;

到 Mongo 目前我有:

db.informacje.aggregate(
    [
           { 
            "$project" : { 
                "_id" : NumberInt(0), 
                "a1" : "$$ROOT"
            }
        },
        { 
            "$lookup" : { 
                "localField" : "id", 
                "from" : "informacje", 
                "foreignField" : "id-1", 
                "as" : "a2"
                        }
        }
        ,
        
       { 
            "$group" : { 
                "_id" : { 
                    "poprzednik" : "$a1.opis_ruchu",
                    "nastepnik"  : "$a2.opis_ruchu"
                }, 
                "COUNT(a1᎐opis_ruchu)" : { 
                    "$sum" : NumberInt(1)
                }
            }
        }
            ])

问题是:当 nastepnik 多一个时,字段 poprzednik 存在一次。

例如在 SQL 中,我有:

poprzednik nastepnik ilosc_wystapien

左左 500

在 Mongo 有:poprzednik nastepnik

左“左”、“左”、“左”……

集合示例:

> db.informacje.find().pretty()
{
        "_id" : ObjectId("5fa7f372fdd610505c57d5d6"),
        "id" : 1,
        "opis_ruchu" : "left"
}
{
        "_id" : ObjectId("5fa7f372fdd610505c57d5d7"),
        "id" : 2,
        "opis_ruchu" : "left"
}
{
        "_id" : ObjectId("5fa7f372fdd610505c57d5d8"),
        "id" : 3,
        "opis_ruchu" : "left"
}
{
        "_id" : ObjectId("5fa7f372fdd610505c57d5d9"),
        "id" : 4,
        "opis_ruchu" : "left"
}

从 id=501 我有 "opis_ruchu" : "right"

标签: mongodb

解决方案


我喜欢做的一件事是使用 MongoDB 指南针——它是一个免费的 GUI 工具,但您可以可视化管道的每个阶段。例如:

在此处输入图像描述

您可以在第一阶段($lookup)之后看到 a2 是一个空数组。你是对的,这是因为“id-1”。使用 $lookup 你不能操作字段,但是你可以在 $lookup 之前使用 $addFields:

addFields 阶段添加 id-1 的 prevId 字段

所以可以看到查找成功了——id=1在a2中什么都没有,因为没有id=0,但是id=2在a2中有一个数组,就是id=1的完整记录。

(使用 Compass 和聚合管道,您可以随时查看各个阶段,这使调试变得更加容易)。

从那里开始,您希望 a2 不是一个数组(您无法避免这种情况,因为查找总是会产生一个数组)。所以你$unwind,它获取数组中的值并为数组中的每个项目创建文档......然后进行分组:

在此处输入图像描述

从组中可以看出,您不需要任何投影,因为您的数据已经是您想要的格式。

所以管道是:

db.informacje.aggregate[{$addFields: {
  prevId: {$subtract: ["$id",1]}
}}, {$lookup: {
  localField: 'prevId',
  from: 'informacje',
  foreignField: 'id',
  as: 'a2'
}}, {$unwind: {
  path: '$a2',
  preserveNullAndEmptyArrays: true
}}, {$group: {
  _id: {
    poprzednik: '$opis_ruchu',
    nastepnik: '$a2.opis_ruchu'
  },
  'sum': {
    $sum: 1
  }
}}]

推荐阅读