需求:要對 topics 問題表根據 teach_id(教師ID),tips._id(問題標籤ID) 字段進行分組統計教師的答題情況生成報表,所以得根據 教師ID,標籤ID 關聯查詢出 教師信息,標籤信息 用作報表展示。
本文基於 MongoDB V3.2 聚合查詢語法,V3.6 可使用更多的特性實現
topics 表數據結構:
{
"_id" : "ffffea46-ab7d-4c19-afa4-fe37709d5300",
"evaluation_type" : 3,
"type" : 3,
"content" : "一般納稅人怎麼結轉成本",
"tips" : [
{
"_id" : 1000,
"tip_name" : "會計基礎"
}
],
"update_at" : NumberLong("1469801351305"),
"author_id" : 10334093,
"timestamp" : NumberLong("1469714932097"),
"race_time" : NumberLong("1469714947334"),
"teach_id" : 10122995,
"last_reply_content" : "這就要看你用的是什麼成本計價方法。",
"last_reply_at" : NumberLong("1469715279859"),
"end_type" : 2
}
從數據結構中可以知道第一步操作是:
根據 teach_id,tips._id 字段進行分組,可得 group(分組) 語句
$group:{
_id:{"teacherId":"$teach_id","tipId":"$tips._id"},
evaluationTypes:{
$push:"$evaluation_type"
},
sum: {$sum: 1}
}
$push($push官方文檔) 可以分組之後把 evaluation_type 字段值 賦給 evaluationTypes 加入到分組之後的返回值中
$sum($sum官方文檔)可得到 teach_id,tips._id 都相同的記錄條數
使用腳本:
db.getCollection("topics").aggregate([
{
$match:{
"race_time" : {"$gte":1522512000000,"$lte":1525103999000},
"type":3
}
},
{
$group:{
_id:{"teacherId":"$teach_id","tipId":"$tips._id"},
evaluationTypes:{
$push:"$evaluation_type"
},
sum: {$sum: 1}
}
}
])
查詢結果:
從結果可以看出 教師:10706280 在這個標籤:1002 下一共搶答了 4 條問題,以及問題的 evaluationTypes(評價類型)
一個分組作爲報表的一條記錄,所以我們得計算報表的總記錄數(總行數)total,所以再對分好組的記錄進行無條件分組(_id: null)
使用腳本:
db.getCollection("topics").aggregate([
{
$match:{
"race_time" : {"$gte":1525103910000,"$lte":1525103999000},
"type":3
}
},
{
$group:{
_id:{"teacherId":"$teach_id","tipId":"$tips._id"},
evaluationTypes:{
$push:"$evaluation_type"
},
sum: {$sum: 1}
}
},
{
$group:{
_id: null,
list:{
$push:"$$ROOT"
},
total: {$sum: 1}
}
}
])
$$ROOT 指定的是分組前的所有數據,所以 list 會把第一次分組得到的數據都帶上
total 是第一次分組之後的記錄數,即一共分了多少組,之後用作分頁總數
查詢結果:
這裏的 group 使用可參考:MongoDB 之 aggregate $group 巧妙運用
教師ID 以及 標籤ID 等信息包含在 list 集合裏,所以需要對 list 進行扁平化($unwind)操作,可參考:MongoDB 聚合嵌入的數組(扁平化數據+管道)
使用腳本:
db.getCollection("topics").aggregate([
{
$match:{
"race_time" : {"$gte":1522512000000,"$lte":1525103999000},
"type":3
}
},
{
$group:{
_id:{"teacherId":"$teach_id","tipId":"$tips._id"},
evaluationTypes:{
$push:"$evaluation_type"
},
sum: {$sum: 1}
}
},
{
$group:{
_id: null,
list:{
$push:"$$ROOT"
},
total: {$sum: 1}
}
},
{
$unwind:"$list"
},
{
$sort: {"list.sum": -1}
},
{
$skip: 0
},
{
$limit: 100
}
])
查詢結果:
扁平化 list 集合數據之後,可根據 教師ID,標籤ID 關聯查詢($lookup)出教師信息,標籤信息
$lookup:
{
from:"users",
localField:"list._id.teacherId",
foreignField: "_id",
as: "users"
}
$lookup(官方文檔)3.2版本 只能根據 localField,foreignField 單條件關聯,3.6版本中 關聯查詢引入 pipeline 管道支持更多更豐富的查詢,對應本文會有更好的解決方案。具體使用可以查看官方文檔
之後便是對數據的多次關聯查詢,以及扁平化操作,下面貼上完整查詢腳本:
db.getCollection("topics").aggregate([
{
$match:{
"race_time" : {"$gte":1522512000000,"$lte":1525103999000},
"type":3
}
},
{
$group:{
_id:{"teacherId":"$teach_id","tipId":"$tips._id"},
evaluationTypes:{
$push:"$evaluation_type"
},
sum: {$sum: 1}
}
},
{
$group:{
_id: null,
list:{
$push:"$$ROOT"
},
total: {$sum: 1}
}
},
{
$unwind:"$list"
},
{
$sort: {"list.sum": -1}
},
{
$skip: 0
},
{
$limit: 100
},
{
$lookup:
{
from:"users",
localField:"list._id.teacherId",
foreignField: "_id",
as: "users"
}
},
{
$lookup:
{
from:"tip_content",
localField:"list._id.tipId",
foreignField: "_id",
as: "childTip"
}
},
{
$lookup:
{
from:"tip_content",
localField:"childTip.parent_tip_id",
foreignField: "_id",
as: "parentTip"
}
},
{
$unwind:"$users"
},
{
$unwind:"$childTip"
},
{
$unwind:"$parentTip"
},
{
$project:{
"teacherId":"$list._id.teacherId",
"teacherName":"$users.real_name_from_nc",
"tuid":"$users.tuid",
"mobile":"$users.mobile",
"tipId":"$childTip._id",
"tipName":"$childTip.tip_name",
"parentTipId":"$parentTip._id",
"parentTipName":"$parentTip.tip_name",
"sum":"$list.sum",
"total":"$total",
"evaluationTypes":"$list.evaluationTypes",
"_id":0
}
}
])
查詢結果:
reference:
Mongodb 3.2 Java 顯示指定字段 條件查詢 官方
Java MongoTemplate查詢返回指定字段及指定數量的數據
Mongoexport error parsing query
關注公衆號,分享乾貨,討論技術,你的支持是我最大的動力!!!