mongo——拆分子节点&数据类型转换&根节点替换

拆分子节点&数据类型转换

    我们知道mongo的某个元素是list,我们可以通过unwind把每个子元素拆解出来,然后再通过group可以很方便的对原本的list进行一个聚合操作,但是如果我们的元素的子节点是还是多个普通元素呢,就不能直接 通过unwind将每个子节点进行拆分。这个时候我们需要通过$objectToArray方法,将多个子节点转换成多个list元素,eg:

db.finance_pay_daily.aggregate()
    .match({time:{$gte:ISODate("2021-01-01T00:00:00.000+08:00")}})
    .project({types:{$objectToArray: "$pay_type_data"}})
    .unwind("$types")

其中project({types:{$objectToArray: “$pay_type_data”}}),将原本的pay_type_data元素下的多个子节点,转换成了list表,并pay_type_data重新命名为types,然后就可以通过unwind方法,将list拆分成多个文档了:

{
  "_id": "20210122",
  "types": {
    "k": "weixin_app",
    "v": {
      "cny": "0.14",
      "balance": 10000,
      "time": 5,
      "user_num": 1,
      "rate": 100
    }
  }
},
{
  "_id": "20210122",
  "types": {
    "k": "alipay_m",
    "v": {
      "cny": "0.03",
      "balance": 10000,
      "time": 3,
      "user_num": 1,
      "rate": 100
    }
  }
}

可以看到通过转变成list元素之后,原本节点名变成了k节点的值,原本节点的值变成了v节点的值。通过这样转变再拆分之后,我们就可以继续group进行聚合操作了,需要注意的是当我们进行聚合运算时,如果被聚合的字段是字符串就无法进行聚合,我们可以通过$toDouble的方式转换成double类型,再进行聚合运算:

db.finance_pay_daily.aggregate()
    .match({time:{$gte:ISODate("2021-01-01T00:00:00.000+08:00")}})
    .project({types:{$objectToArray: "$pay_type_data"}})
    .unwind("$types")
    .group({
          _id: "$types.k", 
          total_cny:{$sum: {$toDouble: "$types.v.cny"}},
          total_balance:{$sum:"$types.v.balance"}
    })
    .sort({_id:-1})
    .limit(100)

以上逻辑转换成kotlin的实现方式如下(java类似):

        val typesAggregation = Aggregation.newAggregation(
            Aggregation.match(Criteria.where("time").gte(startTime).lt(timeQo.endTime)),
            //这里的$符号需要自己加,如果不加的话,spring-data-mongo的api自己不会加,然后就会有问题
            Aggregation.project().and(ObjectOperators.ObjectOperatorFactory("\$pay_type_data").toArray()).`as`("types"),
            Aggregation.unwind("types"),
            Aggregation.group("types.k")
                .sum(ConvertOperators.ConvertOperatorFactory("types.v.cny").convertToDouble()).`as`("total_cny")
                .sum("types.v.balance").`as`("total_balance"))
        adminMongo.aggregate(typesAggregation,"finance_pay_daily",Document::class.java).mappedResults.forEach {
            res["${it["_id"]}_cny"] = it["total_cny"]
            res["${it["_id"]}_balance"] = it["total_balance"]
        }

根节点替换

有时候我们需要将子节点替换为根节点进行聚合操作,可以通过$replaceRoot进行替换

db.finance_pay_daily.aggregate([
    {$match:{time:{$gte:ISODate("2021-01-01T00:00:00.000+08:00")}}},
    {$replaceRoot: { newRoot: "$pay_type_data" }},
    ])

但有时候被我们拿来的子节点有可能是为空的,这时候执行上面的语句是会报错的,这个时候我们可以使用$replaceWith这个方法:

db.finance_pay_daily.aggregate()
    .match({})
    .project({})
    .replaceWith({ $ifNull: [ "$pay_type_data.apple_sandbox", { _id: "1000", missingName: true} ] })
    .sort({time:-1})
    .limit(100)

这个方法同样是将pay_type_data.apple_sandbox这个节点提到根节点,区别是当pay_type_data.apple_sandbox不存在时,是可以拿{ _id: “1000”}这个进行代替的,当然_id这个可以替换成其他的名称,并且可以有多个元素:

db.finance_pay_daily.aggregate()
    .match({})
    .project({})
    .replaceWith({ $ifNull: [ "$pay_type_data.apple_sandbox", { cny: "1000",balance:500, missingName: true} ] })
    .sort({time:-1})
    .limit(100)

甚至替代的元素也是可以拿文档中其他的数据:
这个方法同样是将pay_type_data.apple_sandbox这个节点提到根节点,区别是当pay_type_data.apple_sandbox不存在时,是可以拿{ _id: “1000”}这个进行代替的,当然_id这个可以替换成其他的名称,并且可以有多个元素:

db.finance_pay_daily.aggregate()
    .match({})
    .project({})
    .replaceWith({ $ifNull: [ "$pay_type_data.apple_sandbox", { cny: "$total_cny",balance:"$total_balance", missingName: true} ] })
    .sort({time:-1})
    .limit(100)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值