首页 > 解决方案 > MongoDB:如何查找/删除两个或多个连续重复项?

问题描述

我有这个设备跟踪器,它不断将其位置更新到数据库。

为了跟踪和绘制它的路径,我想删除连续的重复项。现在设备可能会返回到以前的确切位置,所以我不想要不同的位置对象。我可以仅使用查询选项/聚合管道来实现这一点吗?

我会在我的后端代码中实现这个逻辑。记录(包括重复)可能会超过 10k。

输入(示例):

[
  {
    lat: 15.550332,
    lng: 45.664231
  },
  {
    lat: 15.550332,
    lng: 45.664231
  },
  {
    lat: 15.550359,
    lng: 45.664222
  },
  {
    lat: 15.550319,
    lng: 45.664233
  },
  {
    lat: 15.550319,
    lng: 45.664233
  },
  {
    lat: 15.550332,
    lng: 45.664231
  }
]

预期的:

[
  {
    lat: 15.550332,
    lng: 45.664231
  },
  {
    lat: 15.550359,
    lng: 45.664222
  },
  {
    lat: 15.550319,
    lng: 45.664233
  },
  {
    lat: 15.550332,
    lng: 45.664231
  }
]

标签: node.jsmongodbmongoose

解决方案


好的,我能够通过区分连续的坐标来做到这一点。

这个答案被证明很有帮助,我使用了相同的方法并修改了聚合管道,如下所示:

[
  {
    '$group': {
      '_id': 0, 
      'document': {
        '$push': '$$ROOT'
      }
    }
  }, {
    '$project': {
      'newLocation': {
        '$zip': {
          'inputs': [
            '$document', {
              '$concatArrays': [
                [
                  null
                ], '$document.location.lat'
              ]
            }, {
              '$concatArrays': [
                [
                  null
                ], '$document.location.lng'
              ]
            }
          ]
        }
      }
    }
  }, {
    '$unwind': {
      'path': '$newLocation'
    }
  }, {
    '$replaceWith': {
      '$mergeObjects': [
        {
          '$arrayElemAt': [
            '$newLocation', 0
          ]
        }, {
          'prevLat': {
            '$arrayElemAt': [
              '$newLocation', 1
            ]
          }
        }, {
          'prevLng': {
            '$arrayElemAt': [
              '$newLocation', 2
            ]
          }
        }
      ]
    }
  }, {
    '$set': {
      'lat_difference': {
        '$subtract': [
          '$location.lat', '$prevLat'
        ]
      }, 
      'lng_difference': {
        '$subtract': [
          '$location.lng', '$prevLng'
        ]
      }
    }
  }, {
    '$match': {
      'lat_difference': {
        '$ne': 0
      }, 
      'lng_difference': {
        '$ne': 0
      }
    }
  }
]

大多数管道在另一个答案中进行了详细解释,但总而言之,它的作用是尝试将所有位置对象分组到一个数组中(我在上面跳过了一些预过滤阶段,因为它与这里的结果无关并且只是投影和匹配一些值)。我添加了分组阶段,因为我的原始 JSON 还具有除位置对象之外的其他键。分组后,它将使用其前身的坐标更新每个对象。

最后两个阶段是我过滤结果的地方。

关键是计算 2 个连续坐标(lat 和 lng)之间的差异,并返回差异不等于 0 的那些记录。

我在大约 1k 条记录上对其进行了测试,到目前为止,它一直在给我想要的结果,但还需要做更多。

虽然,我仍然不确定是否有更好的方法,但现在就可以了。我愿意接受建议。


推荐阅读