我们将了解
$group
阶段中的
_id
字段,并查看一些构建聚合阶段中
_id
的最佳实践。让我们来看一下这个查询:
db.companies.aggregate([{
$match: {
founded_year: {
$gte: 2010
}
}
}, {
$group: {
_id: {
founded_year: "$founded_year"
},
companies: {
$push: "$name"
}
}
}, {
$sort: {
"_id.founded_year": 1
}
}]).pretty()
![MongoDB使用文档方法进行$group](https://lh3.googleusercontent.com/cZdysCDFCMxAH0aA5UaCSKgsa23oINU-cC81I72xoB-dJaTYoCAC_Z29Jbf4DYgCPPnadfThclubc4d6bYGEGKI40-mp-Nqh5NSKezeS1W6HHzy7HCVi-BYLWNf2Qzo_lGtvDEjdS1bijrMao9pimLRSophJHrIeF0yq4DcutY6CG9l1DUarH4Chz1jjzcozOkgsU44W0AoAVX413CzX-Bm4hwR-z_XCNXDMAAuJOJUgm5tSGAyvanCbegqFc5MIH3bcwY21-BYlr2PZbX8wp9veq2h6l9Igiu1Ghw73WxMwzEKy7Q1smjigWNJUAwNJArJxdahO-WeWLDtNC0rQltt0Q5-eeKtei0I1Vr117qCyerREiUunDyZt7cOK9rDI0BqoFGQKaAuST5XK95BrUOj-S7PP-YcpsxiQmWQZgOilr3x-muwxy48MxM-qhvEkFYIWbDjS_H5RzRY17jJkFgPStt8WkbcNT6FwOlNLWhW3pXm0tbcvP37jOzZy_IZvatZEcYpCSuiYrEMvqdDB4tmV6kRcIxbaZ3wlZL-zGWopfo98HyLQqziwowKhr1v3Fp1ueY_m9mSOG3vH2dnj_wM384TaB5IB3Pxwjm4lTHSbkscK=w323-h246-no)
有一件事可能不太清楚,为什么_id
字段是这样构建的“文档”方式?我们也可以这样做:
db.companies.aggregate([{
$match: {
founded_year: {
$gte: 2010
}
}
}, {
$group: {
_id: "$founded_year",
companies: {
$push: "$name"
}
}
}, {
$sort: {
"_id": 1
}
}]).pretty()
We do not use this approach for MongoDB $group because the output documents do not explicitly state the meaning of the numbers. This lack of clarity can lead to confusion when interpreting the documents. Instead, we can group an
_id
document with multiple fields.
db.companies.aggregate([{
$match: {
founded_year: {
$gte: 2010
}
}
}, {
$group: {
_id: {
founded_year: "$founded_year",
category_code: "$category_code"
},
companies: {
$push: "$name"
}
}
}, {
$sort: {
"_id.founded_year": 1
}
}]).pretty()
![在MongoDB中使用$group对具有多个字段的_id文档进行分组](https://lh3.googleusercontent.com/Dp75pUue_R3I8DI18FVuErEUeBNBomiGTQcVO45FoBeHgu9H_MAfGSpgmxOyVQddvuNTnv_oDMIoQWMsrQKmETdDLjBk8Yj6vh8cLmxrpbZd6u2g2qBJWkgBNvQRKVIpflDo9-7-tdOhneJ6QC_DqC4Nhb68Yac42rlzNeHjlrz8lKYLZFJMQ79m3dodgI6bI9JGHHKPfdHE7X_ypVxbARpqvYO8J6lh4Rtg6VshULFnskCQHBQYsCXfs3RtSaNi3t-D5dGSbf7RUuoTFaXxWGco6lBiALZze8Dfnen2wPHhTVDzqzDthR1o7NwB_VviKSMtFHZsb8B9lxzRy8X3DxCx297p8qG1R6xHKbw5lG5rawpIs-HCBkreXavm3MDwhrLbAnZuimFLTzVqxYBeICKSX1uCnzRKNKZkUAdhSDm4tof4nAJkkkP5RcOU7r7dNGLUMiK9bdHqqZVoTLopwRY8dcSW7OfPky3kyk5LKlGAG2jUJBaDY95WojrnSkZ2e8f7m6oocAaXPevZ0oqpg_Tp4jAoftsUoqcr3az3_3vL1JPweM3eNnyQQWIQUrvsOOIEGO3DWYTDE12zEy0ZBeoVNWVgNKINz0DA-aADQNVVL0aP=w354-h219-no)
$push
会将元素推入生成数组中。通常,可能需要在提升字段到上一层级后进行分组:
db.companies.aggregate([{
$group: {
_id: {
ipo_year: "$ipo.pub_year"
},
companies: {
$push: "$name"
}
}
}, {
$sort: {
"_id.ipo_year": 1
}
}]).pretty()
![MongoDB将组上升到更高级别](https://lh3.googleusercontent.com/XqzUb0ni8-HrWSEsiUydzqXjJX0snqmU5NaHaZzKoubs3iy8Zp20F18g-fKt3cSiJucKtAkc72L2I7LI0BWrWmCL29ZmOZueKt3HCcONkTVnwRWPXkHWmotQ8-8ebeN2rKIYP0J6GWbfSQkjVq4vTgnoqnSIZv0CSRhSbh3NhjYv8xLxSf_bYvP6QNGUndBbJPwlE5wmCCpmiuNhVRgTz3XNkdYFsjbzzFUSrarnNtls9k9WnLMRlyx8_VWP-7iwWoQHY2WlLdff7VNAUF6IC4ih0mA8wV6GxyX5l_Bw9AqRj8rCgeDhGCpNzteUg0WTfxae0xyVqe73GjaA-o6j9mx-qch1RC1gf1xWXUEhdcxz2hBlJS6JjXPW95o43wNr-YJm-TAyp8Y38aLe7vgw75fO6Jl5mq3AGnoBrBFqceK6luEhe76QupAPQalWabE7JDAp4dEZ3ruvX7998vHR1afrShPG1DyP8DN267ef7UookJNbpq1scFqbX5DxNQZqCYZ89re5uW3dKiDq-Hqnx-h9a5oCLJ03HNapyg9i3T3e96hsPDAiIWahlQ0b_33jzZhiT1premDidg3pLIr_DHniV0YVSiK0Sffm7hN4MUpVlOBf=w280-h123-no)
同时,将作为文档的表达式作为_id
键也是完美的。
db.companies.aggregate([{
$match: {
"relationships.person": {
$ne: null
}
}
}, {
$project: {
relationships: 1,
_id: 0
}
}, {
$unwind: "$relationships"
}, {
$group: {
_id: "$relationships.person",
count: {
$sum: 1
}
}
}, {
$sort: {
count: -1
}
}])
![It's also perfect to have an expression that resolves to a document as a _id key in MongoDB](https://lh3.googleusercontent.com/GrLY0VWm7RExvL4So548j-OPoeBlcB4t8YlsPNfWuvM1zLHEwf2XaJly-Cg-wqu8_avEz3qYiYvY2quN3q4eVnok9DhAwAF8E-MPw3q1orDOipb-9mXnLzZPdNgIyAlVPBo3oQuPChXa1flWvNNz9xLD1QHQN_H4UiEo4SB2FONhMZ5QlebWfSSPiJlpE4LJupomYINf1kiFx-mD2p_Hfol7HB2VZEUxT4kgOlHo02hvXWh0k-CHr7sloJXnuEWM_cKIajOGyZLVbfsgEtf-2lMLJMQOIqcPP6fJ54sWjsVr2dMD6b7QtBUOgaR0E_-z_8Zik9wkHA3d6ShpUuPUaFpbHPre8UwVCRVOBcTuryn8JoRTHrVso4HshELeNp4XZTnz1oFDVKdFSOJ3eawiO3_0SWaNr6KJltgxAOAODX80nYp8r7rawWtMiCSX_GgmV7UELNKHemACsoykNpmTjqc5eWBx0B_HuhJmxN9sZY2Y0pDmaQdOwzKPMTTBFZyrwyLEAegARNM3DcEi1suRWnJWJZBhcpArVNggHpstSMK9BbM-fdvUcR6pGdtXE3a4_S6A28zDf68OqELWuFzNe5WMW1scoyAkg4svzvHJQZ_aCCdx=w346-h101-no)