[mongodb]exception: $concat only supports strings, not NumberInt32

今天在用mongodb操作aggregation的时候出现这个问题,我是想格式化日期,例如”2013-10-17 04:41:37 UTC”变成”10月17日”,

'fdate' => { '$concat' => ['$date.month', '月', '$date.day', '日'] }

出现 exception: $concat only supports strings, not NumberInt32

原来$concat只能操作字符串,不支持数字类型,解决办法是用$substr

$date形如’2013-10-13 11:17:18 UTC’

'fdate' => { '$concat' => [ {$substr=>['$date', 5, 2]}, '月', {$substr=>['$date', 8, 2]}, '日'] }

$substr接受两个参数,一个是字符串的起点,一个是截取的字符串的长度。

再看mongodb的分组group

在之前的记一次Mongodb性能调优文章中,最后使用了aggregation来做聚合查询,今天又有一个新的需求,需要在之前按日期聚合的基础上再按照店铺来聚合(说实话,到这里已经感觉到非关系数据库这方面的弱势了)。

幸运的是aggregation的操作其实是类似于管道(pipeline),可以进行多次group,这样就方便多次处理数据,得到想要的结果。

def diary_with_shop(opts = {})
  page       = opts[:page] || 1
  per_page   = opts[:per_page] || 20
  conditions = [{'$match' => {user_id: self.id, deleted_at: nil}}]
  conditions << {'$project' => {
    'year'  => {'$year'      => '$created_at'},
    'month' => {'$month'     => '$created_at'},
    'day'   => {'$dayOfYear' => '$created_at'},
    'date'  => '$created_at', 'shop_id' => 1
  }}
  conditions << {'$group' => {
    '_id' => {
      'year' => '$year', 'month' => '$month', 'day' => '$day', 'shop_id' => '$shop_id'
    },
      'date'  => { '$min' => '$date' },
      'food_stories' => { '$push' => '$_id' }
    }}
  conditions << {'$group' => {
    '_id'   => {
      'year' => '$_id.year', 'month' => '$_id.month', 'day' => '$_id.day'
     },
    'date'  => { '$min' => '$date' },
    'shops' => { '$push' => { 'shop_id' => '$_id.shop_id', 'food_stories' => '$food_stories' } }
  }}
  conditions << {'$sort'  => {'date' => -1}}
  conditions << {'$skip'  => (page.to_i - 1)*per_page.to_i}
  conditions << {'$limit' => per_page.to_i}
  Model.collection.aggregate(conditions)
end

如果对比上次的代码,可以发现这里多了一个group操作,第一个group的`_id`带上了shop_id,带上的shop_id在第二个group中又进行了分组,最后得到想要的结果。

在这里,shop只是id,如果想返回shop的名字,可以用类似于关系型数据库的join操作吗?

答案是不行,文档型数据库只能操作一个collection。那如果想得到shop_name,难道需要再次查询吗?尽量不要这样,这样会丧失aggregation的性能,所以如果你有字段在collection中没有,那么—

最好的办法就是直接复制加上去,不用考虑数据库的冗余,这样才能发挥文档型数据库的优势。

其实每个数据库都不可能取代另一个数据库,只有把数据库自有的特点发挥出来,才能达到性能的最大化,所以如果mongodb里面有很多的外键关联,那么可以考虑是否数据库的设计偏离了mongodb的本质。