【问题标题】:MongoDB - Aggregate: How to group by depending on queryMongoDB - 聚合:如何根据查询进行分组
【发布时间】:2020-02-01 02:51:32
【问题描述】:

我想聚合一个给定类型的集合。类型来自查询字符串,可以是日、月或年。根据用户选择我想要分组的类型。 例如:如果用户选择“月”,我想按月分组。

Event.aggregate([
    {
      $lookup: { from: Product.collection.name, localField: 'product', foreignField: '_id', as: 'product' }
    },
    {
      $group: {
        _id: { $month: { date: "$date" } },
        price: { $sum: "$price" },
        result: { $mergeObjects: { name: "$product.name", _id: "$product._id" } },
        count: { $sum: 1 }
      },
    },
  ]).then(response => {
    console.log(response)
    res.send(response)
  })

我不知道如何找到干净的解决方案。 到目前为止,我发现的唯一方法是在 Model.aggregate([]) 之前使用 if 条件 ...

  if (req.query.dateAvailability && req.query.dateAvailability === 'month') {
    Event.aggregate([
      {
        $lookup: { from: Product.collection.name, localField: 'product', foreignField: '_id', as: 'product' }
      },
      {
        $group: {
          _id: { $month: { date: "$date" } },
          price: { $sum: "$price" },
          result: { $mergeObjects: { name: "$product.name", _id: "$product._id" } },
          count: { $sum: 1 }
        },
      },
    ]).then(response => {
      console.log(response)
      res.send(response)
    })
  } else if (req.query.dateAvailability && req.query.dateAvailability === 'day') {
    Event.aggregate([
      {
        $lookup: { from: Product.collection.name, localField: 'product', foreignField: '_id', as: 'product' }
      },
      {
        $group: {
          _id: { $dateToString: { format: "%d-%m-%Y", date: "$date" } },
          price: { $sum: "$price" },
          result: { $mergeObjects: { name: "$product.name", _id: "$product._id" } },
          count: { $sum: 1 }
        },
      },
    ]).then(response => {
      console.log(response)
      res.send(response)
    })
  } else if (req.query.dateAvailability && req.query.dateAvailability === 'year') {
    Event.aggregate([
      {
        $lookup: { from: Product.collection.name, localField: 'product', foreignField: '_id', as: 'product' }
      },
      {
        $group: {
          _id: { $year: { date: "$date" } },
          price: { $sum: "$price" },
          result: { $mergeObjects: { name: "$product.name", _id: "$product._id" } },
          count: { $sum: 1 }
        },
      },
    ]).then(response => {
      console.log(response)
      res.send(response)
    })
  }

模型事件:

const EventSchema = new Schema({

  client: {
    type: [{
      type: Schema.Types.ObjectId,
      ref: 'Client'
    }]
  },

  product: {
    type: [{
      type: Schema.Types.ObjectId,
      ref: 'Product'
    }]
  },

  date: {
    type: Date,
    maxlength: 64,
    lowercase: true,
    trim: true
  },

  place: {
    type: String,
    maxlength: 1200,
    minlength: 1,
  },

  price: {
    type: Number
  },

  comment: {
    type: String,
    maxlength: 12000,
    minlength: 1,
  },

  status: {
    type: Number,
    min: 0,
    max: 1,
    default: 0,
    validate: {
      validator: Number.isInteger,
      message: '{VALUE} is not an integer value'
    }
  },
},
  {
    toObject: { virtuals: true },
    toJSON: { virtuals: true }
  },
  {
    timestamps: true
  },
);

【问题讨论】:

  • 谢谢汤姆斯巴伯特和乔什巴尔奇蒂斯,这两种解决方案都很完美,而且比我的更干净(我测试过它们)。很高兴知道在这种情况下也没有消除逻辑的神奇解决方案。我会接受汤姆的回答,因为它是第一个,但两者都是使代码更清晰的好方法。

标签: mongodb aggregation-framework aggregate


【解决方案1】:

没有什么神奇的解决方案可以消除逻辑的使用,在这种情况下,它总是需要的。

但是我们可以让代码更性感一点:

let groupCond;
if (req.query.dateAvailability && req.query.dateAvailability === 'month') {
    groupCond = { $month: { date: "$date" } };
} else if (req.query.dateAvailability && req.query.dateAvailability === 'day') {
    groupCond = { $dateToString: { format: "%d-%m-%Y", date: "$date" } };
} else if (req.query.dateAvailability && req.query.dateAvailability === 'year') {
    groupCond =  { $year: { date: "$date" } };
}

Event.aggregate([
    {
        $lookup: { from: Product.collection.name, localField: 'product', foreignField: '_id', as: 'product' }
    },
    {
        $group: {
            _id: groupCond,
            price: { $sum: "$price" },
            result: { $mergeObjects: { name: "$product.name", _id: "$product._id" } },
            count: { $sum: 1 }
        },
    },
]).then(response => {
    console.log(response)
    res.send(response)
})

【讨论】:

    【解决方案2】:

    您的问题没有灵丹妙药,逻辑必须发生在某个地方。如果您使用的是 mongodb 3.4 或更高版本,则在查询外部使用 if 语句或在查询内部使用 $switch 运算符。

    {"$group": {
      "_id":{ 
        "$switch": { 
          "branches": [
            { "case":{ "$eq": [ { "$literal": "day" }, { "$literal": req.query.dateAvailability } ] },
             "then": { $dateToString: { format: "%d-%m-%Y", date: "$date" } } },
            { "case":{ "$eq": [ { "$literal": "month" }, { "$literal": req.query.dateAvailability } ] },
             "then": { $month: { date: "$date" } } },
            { "case":{ "$eq": [ { "$literal": "year" }, { "$literal": req.query.dateAvailability } ] },
             "then": { $year: { date: "$date" } } }
          ], 
          "default": { ... default logic for when dateAvailability isn't set ... } 
        } 
      }
      ... rest of the group operation
    } }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-19
      • 2020-11-06
      • 1970-01-01
      • 1970-01-01
      • 2020-06-29
      • 2017-09-19
      • 2015-05-30
      • 2023-01-20
      相关资源
      最近更新 更多