mongoose聚合——$project
$project:修改输入文档的结构,可以用来增加、删除、修改域,或创建文档,也可用于创建计算结果以及嵌套文档。
数据表
//Articles
[{ "_id":"5eb4cb0dcf4cc329300df1de","title":"dfgtest文章",
"publishDate":"2020-05-22T00:00:00.000Z", "content":"<p>ABCdefg</p>",
"val":1, "setting":{"isTop":true}, }, { "_id":"5eb4ec52d3a5c90fecd0e43e","title":"托尔斯泰2",
"val":1,
"publishDate":"2020-05-03T00:00:00.000Z", "content":"<p>ABCD</p>", "setting":{"isTop":false}, }]
//Users
[{ "_id":"5eae1e25c938a74ec0e5fb7a", "username":"mmtest", "email":"10001001@test.com", }, { "_id":"5eb12980c7bb9821ac08fcf2", "username":"zhangsan", "email":"10001002@test.com" }]
代码
这里的代码只显示query部分,文末附上完整代码。
Model.aggregate([ ...query ]) //Model表示Users或Articles
1. 更改字段名
代码:将_id的字段名修改为id,username的字段名修改为name。
const query = [ { $project: { _id: 0, // 默认情况下_id是包含的,将_id设置为0|false,则选择不包含_id,其他字段也可以这样选择是否显示。 id: '$_id', name: '$username' } } ]
原始数据与结果:
[{
"_id":"5eae1e25c938a74ec0e5fb7a",
"username":"mmtest",
"email":"10001001@test.com",
},
...]
---聚合后---
[{ id: 5eae1e25c938a74ec0e5fb7a, name: 'mmtest' }, ...]
2.对数据中对象进行操作
代码:提取setting对象中的isTop;创建sub对象
const query = [ { $project: { _id: 0, title: '$title', isTop: '$setting.isTop', sub: { date: '$publishDate' } } } ]
原始数据与结果:
[{ "_id":"5eb4cb0dcf4cc329300df1de","title":"dfgtest文章",
"publishDate":"2020-05-22T00:00:00.000Z", "content":"<p>ABCdefg</p>","val":1, "setting":{"isTop":true}, },
...]
---聚合后---
[ { title: 'dfgtest文章', isTop: 'true', sub: { date: 2020-05-22T00:00:00.000Z } },
... ]
3.四则运算
代码:对val进行加、减、乘、除、模2
加法($add)、减法($subtract)、乘法($multiply)、除法($divide)、求模($mod)
const query = [ { $project: { _id: 0, title: '$title', add: { $add: ['$val', 2] }, multiply: { $multiply: ['$val', 2] }, subtract: { $subtract: ['$val', 2] }, divide: { $divide: ['$val', 2] }, mod: { $mod: ['$val', 2] } } } ]
原始数据与结果:
[{ "_id":"5eb4cb0dcf4cc329300df1de","title":"dfgtest文章", "publishDate":"2020-05-22T00:00:00.000Z", "content":"<p>ABCdefg</p>", "val":1, "setting":{"isTop":true}, }, ...] ---聚合后--- [ { title: 'dfgtest文章', add: 3, multiply: 2, subtract: -1, divide: 0.5, mod: 1 }, ... ]
4.关系运算
代码:对val进行关系运算
(1)将Boolean值转化为数字("$cmp"),cmp:{$cmp:['$setting.isTop',false]},如果setting.isTop=false,那么cmp为0;如果setting.isTop=true,那么cmp为1,如果setting.isTop不是Boolean类型或为null,cmp为-1。
(2)等于("$eq")、大于("$gt")、大于等于("$gte")、小于("$lt")、小于等于("$lte")、不等于("$ne")这些返回值都是 boolean 值类型的,如果没有val值,那么会默认val=0。
(3)判断 null ("$ifNull"),ifNull:{$ifNull:['$val',etc]},如果val上不为Null,则ifNull就是val的值;如果val为Null,那么ifNull就是etc的值。
const query = [ { $project: { _id: 0, title: '$title', cmp: { $cmp: ['$setting.isTop', false] }, eq: { $eq: ['$val', 2] }, gt: { $gt: ['$val', 2] }, gte: { $gte: ['$val', 2] }, lt: { $lt: ['$val', 0] }, lte: { $lte: ['$val', 2] }, ne: { $ne: ['$val', 2] }, ifNull: { $ifNull: ['$val', 2] } } } ]
原始数据与结果:
[{ "_id":"5eb4cb0dcf4cc329300df1de","title":"dfgtest文章", "publishDate":"2020-05-22T00:00:00.000Z", "content":"<p>ABCdefg</p>", "val":1, "setting":{"isTop":true}, }, { "_id":"5eb4ec52d3a5c90fecd0e43e","title":"托尔斯泰2",
"publishDate":"2020-05-03T00:00:00.000Z", "content":"<p>ABCD</p>", "setting":{"isTop":false}, }]
---聚合后---
[
{
title: 'dfgtest文章',
cmp: 1,
eq: false,
gt: false,
gte: false,
lt: false,
lte: true,
ne: true,
ifNull: 1
},
{
title: '托尔斯泰2',
cmp: 0,
eq: false,
gt: false,
gte: false,
lt: true,
lte: true,
ne: true,
ifNull: 2
}
]
5.字符串操作
代码:
连接("$concat")、截取("$substr")、转小写("$toLower")
const query = [ { $project: { _id: 0, title: '$title', concat1: { $concat: ['$title', '+1+1'] }, concat2: { $concat: ['$title', '$content'] }, substr:{ $substr: ['$title', 0,3] }, toLower:{ $toLower: '$content'}, } } ]
原始数据与结果:
[{ "_id":"5eb4cb0dcf4cc329300df1de","title":"dfgtest文章", "publishDate":"2020-05-22T00:00:00.000Z", "content":"<p>ABCdefg</p>", "val":1, "setting":{"isTop":true}, }, ...] ---聚合后--- [ { title: 'dfgtest文章', concat1: 'dfgtest文章+1+1', concat2: 'dfgtest文章<p>ABCdefg</p>', substr: 'dfg', toLower: '<p>abcdefg</p>' }, ... ]
6.日期
代码:
$year年份,$month月份,当月$dayOfMonth,$dayOfYear当年过了多少天
const query = [ { $project: { _id: 0, title: '$title', date:{ year:{$year:'$publishDate'}, month:{$month:'$publishDate'}, dayOfMonth:{$dayOfMonth:'$publishDate'}, dayOfYear:{$dayOfYear:'$publishDate'} } } } ]
原始数据与结果:
[{ "_id":"5eb4cb0dcf4cc329300df1de","title":"dfgtest文章", "publishDate":"2020-05-22T00:00:00.000Z", "content":"<p>ABCdefg</p>", "val":1, "setting":{"isTop":true}, }, ...] ---聚合后--- [ { title: 'dfgtest文章', date: { year: 2020, month: 5, dayOfYear: 143 } }, ... ]
完整代码
const Articles = require('../../model/articles'); const Users = require('../../model/users'); //使用$project修改输入文档的结构,可以用来增加、删除、修改域,或创建文档,也可用于创建计算结果以及嵌套文档。 //-----------------------------1--------------------------- /** * 结果user只输出id,name */ async function project1() { const query = [ { $project: { _id: 0, // 默认情况下_id是包含的,将_id设置为0,则选择不包含_id id: '$_id', name: '$username' } } ] await usersAggregate(query); } //-----------------------------2--------------------------- //在mongoose中,使用以下代码会报错 /* async function project2(){ const query='username email -_id'; await usersAggregate(query); } */ //-----------------------------3--------------------------- /** * 对数据中对象进行操作 */ async function project3() { const query = [ { $project: { _id: 0, title: '$title', isTop: '$setting.isTop', val: '$val', sub: { date: '$publishDate' } } } ] await articlesAggregate(query); } //-----------------------------4--------------------------- //加法($add)、减法($subtract)、乘法($multiply)、除法($divide)、求模($mod) /** * 对数据val中进行四则运算操作,val=1 */ async function project4() { const query = [ { $project: { _id: 0, title: '$title', add: { $add: ['$val', 2] }, multiply: { $multiply: ['$val', 2] }, subtract: { $subtract: ['$val', 2] }, divide: { $divide: ['$val', 2] }, mod: { $mod: ['$val', 2] } } } ] await articlesAggregate(query); } //-----------------------------5--------------------------- //关系运算:将Boolean值转化为数字("$cmp"),cmp:{$cmp:['$setting.isTop',false]},如果setting.isTop=false,那么cmp为0;如果setting.isTop=true,那么cmp为1,如果setting.isTop不是Boolean类型或为null,cmp为-1 //等于("$eq")、大于("$gt")、大于等于("$gte")、小于("$lt")、小于等于("$lte")、不等于("$ne")、这些返回值都是 boolean 值类型的。 //判断 null ("$ifNull"),ifNull:{$ifNull:['$val',etc]},如果val上不为Null,则ifNull就是val的值;如果val为Null,那么ifNull就是etc的值。 /** * 关系运算 */ async function project5() { const query = [ { $project: { _id: 0, title: '$title', cmp: { $cmp: ['$setting.isTop', false] }, eq: { $eq: ['$val', 2] }, gt: { $gt: ['$val', 2] }, gte: { $gte: ['$val', 2] }, lt: { $lt: ['$val', 0] }, lte: { $lte: ['$val', 2] }, ne: { $ne: ['$val', 2] }, ifNull: { $ifNull: ['$val', 2] } } } ] await articlesAggregate(query); } //-----------------------------6--------------------------- //字符串操作 //连接("$concat")、截取("$substr")、转小写("$toLower") /** * 字符串操作 */ async function project6() { const query = [ { $project: { _id: 0, title: '$title', concat1: { $concat: ['$title', '+1+1'] }, concat2: { $concat: ['$title', '$content'] }, substr:{ $substr: ['$title', 0,3] }, toLower:{ $toLower: '$content'}, } } ] await articlesAggregate(query); } //-----------------------------7--------------------------- //日期:$year年份,$month月份,当月$dayOfMonth,$dayOfYear当年过了多少天 /** * 日期 */ async function project7() { const query = [ { $project: { _id: 0, title: '$title', date:{ year:{$year:'$publishDate'}, month:{$month:'$publishDate'}, dayOfMonth:{$dayOfMonth:'$publishDate'}, dayOfYear:{$dayOfYear:'$publishDate'} } } } ] await articlesAggregate(query); } /** * users聚合结果模板 * @param {Array} query 聚合的参数 */ async function usersAggregate(query) { try { const result = await Users.aggregate([ ...query ]) console.log(result); } catch (err) { console.log(query) console.log("聚合失败...", err) } } /** * articles聚合结果模板 * @param {Array} query 聚合的参数 */ async function articlesAggregate(query) { try { const result = await Articles.aggregate([ ...query ]) console.log(result); } catch (err) { console.log(query) console.log("聚合失败...", err) } } function main() { // project2(); // project3(); // project4(); // project5(); project6(); // project7(); } main();
参考致谢:
https://blog.csdn.net/github_38589282/article/details/76735688
https://blog.csdn.net/qq_18948359/article/details/88777314
https://www.runoob.com/mongodb/mongodb-aggregate.html
如有错误,请指正~