在MongoDB / Mongoose中聚合数组数组

时间:2018-03-01 05:18:01

标签: javascript mongodb mongoose

我正在尝试将集合聚合到一个文档数组中。这就是我想要的样子。

[
  {
    _id: ObjectId,
    points: [
      [longitude, latitude],
      [longitude, latitude],
      [longitude, latitude]
    ]
  },
  {
    _id: DifferentObjectId,
    points: [
      [longitude, latitude],
      [longitude, latitude],
      [longitude, latitude]
    ]
  }
]

这是我的模特。

const mongoose = require('mongoose');

const workSchema = new mongoose.Schema({
  fieldId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Field'
  },
  dayId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Day'
  },
  workerId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Worker'
  },
  contractorId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Contractor'
  },
  ownerId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Owner'
  },
  points: [{
    point: {
      type: {
        type: String,
        default: 'Point'
      },
      // longitude, latitude
      coordinates: [Number]
    },
    category: {
      type: String,
      enum: ['entry', 'exit', 'sos', 'in', 'out']
    },
    createdAt: {
      type: Date,
      default: Date.now
    }
  }]
},
{
  timestamps: true
});

workSchema.index({ 'points.point': '2dsphere' });

module.exports = mongoose.model('Work', workSchema);

这是我的聚合逻辑。

const work = await Work.aggregate([
    {
      $match: {
        contractorId: req.user.contractorId
      }
    },
    {
      $group: {
        _id: '$fieldId',
        points: {
          $push: '$points.point.coordinates'
        }
      }
    }
  ]);

这是我最终得到的。请注意阵列嵌套的额外层。

    [
  {
    _id: ObjectId,
    points: [
      [
        [longitude, latitude],
        [longitude, latitude],
        [longitude, latitude]
      ]
    ]
  },
  {
    _id: DifferentObjectId,
    points: [
      [
        [longitude, latitude],
        [longitude, latitude],
        [longitude, latitude]
      ]
    ]
  }
]

我已经测试过对其他字段进行分组,例如ownerId,它的工作方式与预期完全相同。我认为这与我从嵌入对象数组中存在的字段进行分组这一事实有关,但我不知道如何解决它。任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:2)

首先,你需要展开数组。

const work = await Work.aggregate([{
        $match: {
            contractorId: req.user.contractorId
        }
    },
    {
        $unwind: '$points'
    },
    {
        $group: {
            _id: '$fieldId',
            points: {
                $push: '$points.point.coordinates'
            }
        }
    }
]);

输出类似于

[{
        _id: ObjectId,
        points: [
            [longitude, latitude],
            [longitude, latitude],
            [longitude, latitude]
        ]
    },
    {
        _id: DifferentObjectId,
        points: [
            [longitude, latitude],
            [longitude, latitude],
            [longitude, latitude]
        ]
    }
]

答案 1 :(得分:1)

你尝试的是正确的。您可以再添加一个平台来展平数组(points

...
{
  $addFields: {
    'points': {
      $reduce: {
        input: '$points',
        initialValue: [],
        in: { $concatArrays: ["$$value", "$$this"] }
      }
    }
  }
}

请参见此处的示例以展平数组,https://docs.mongodb.com/manual/reference/operator/aggregation/reduce/#computing-a-single-reduction