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
如有错误,请指正~

浙公网安备 33010602011771号