cover

$project()

这个方法就是对要输出的每个document里面的字段进行自定义,可以定义要显示的字段,可以对字段进行重命名,进行重命名,甚至一个字段拆分为多个字段,但是不会改变数据库里面的document结构
MySchema = {  
    title: 'slj',
    content: 'slj forever',
    author: 'sjf',
    tags: ['Love'],
    time: '2016-7-25'
}
Model.aggregate([{$project: {content: 1}}])  
下面的的结果清楚显示只包含了content这一字段(ObjectId是mongodb的特点,你懂得)就是说在$project里面你写了什么字段输出结果就只包含这个字段加上ObjectId,content后面的属性只要不是0或者false这些进行判断值会为false或者会被隐式转换为false的值就可以。所以要去除ObjectId就加一条_id: 0就可以了
> db.tests.aggregate([{$project: {content: 1}}])
{
    "result" : [{
        "_id" : ObjectId("579756e87f2f69c657ef2ec8"),
        "content" : "slj forever"
    }],
    "ok" : 1
}
下面的结果显示怎么进行拆分字段($substr顾名思义大家都知道就是取字串,然后取字串怎么用大家都知道,拆分也就是通过这个取字串来的)
> db.tests.aggregate([{$project:{time:{year:{$substr:["$time",0,4]},month: {$substr: ["$time",5,6]}}}}])
{
    "result" : [
        {
            "_id" : ObjectId("579756e87f2f69c657ef2ec8"),
            "time" : {
                "year" : "2016",
                "month" : "7-25"
            }
        }
    ],
    "ok" : 1
}
还有一些那些功能可以自己去试一下

$group()

这个方法就是按照给定表达式组合结果 ,比如说你想根据某个字段对信息进行分类
> db.tests.aggregate({$group: {_id: "$tags"}})
{
    "result" : [
        {
            "_id" : [
                "Love",
                "Baby"
            ]
        },
        {
            "_id" : [
                "honey"
            ]
        }
    ],
    "ok" : 1
}
首先那个通过查找的属性名一定要是_id,就是唯一标识符,然后后面的可以直接写$加分组的字段名,当然也可以进行重命名,如:
db.tests.aggregate({$group: {_id: {rename: "$tags"}}})  
    "_id" : {
        "rename" : [
            "Love",
            "Baby"
        ]
    }
但是$group不适合大数量的数据进行分组,因为是在内存中进行的

$sort()

大家一看就知道这 个管道函数使用来进行排序的,确实如此,而且规则也和js差不多,-1表示降序,1表示升序
    .$sort和其他管道函数一起用的时候最好放在前面,只会对后面管道函数选出的内容进行排序
    .$sort()也是在内存中进行的,所以当需要排序的内容达到物理内存的10%就会报错
    .当多个属性进行排序冲突时,按照最先进行排序的属性进行排序
 db.tests.aggregate({$sort: {content: -1,time: -1}})这俩个时冲突的就会按照content进行降序排序
 db.tests.aggregate({$sort: {time: -1,content: -1}})就会按照time进行降序排序

$unwind()

这个函数就是对对应的属性进行拆分然后插入到document,就是说如果对上面的tags:["Love","Baby"]进行unwind就会发生这个document会被拆分成俩个docuemnt,一个包含tags: "Love",一个包含"Baby",其他字段的内容都是一样的,eg:
> db.blogs.aggregate({$project:{tags: 1}},{$unwind: "$tags"})
{
    "result" : [
        {
            "_id" : ObjectId("579601837bd410473d2d064d"),
            "tags" : "Love"
        },
        {
            "_id" : ObjectId("5796019b7bd410473d2d064e"),
            "tags" : "Love"
        },
        {
            "_id" : ObjectId("5796019b7bd410473d2d064e"),
            "tags" : "Honey"
        }
    ],
    "ok" : 1
}

$skip()

$skip()就是跳过的意思,就是当我们对数据进行选择的时候可以从当前位置忽略一定数量的document ,$skip()的参数只能为正整数
db.tests.aggregate({$skip : 5})  

$match()

$macth()管道函数其实和find()方法没什么区别,里面的匹配条件和find()的查找条件是一样的写法
db.tests.aggregate({$match: {time: {$gte: 2016-7-01}}})  

$limit()

$limit()就是限制要查询的文档数量
db.tests.aggregate({$limit: 5})  
从tests这个collections开始忽略五个document

$skip()和$limit()的执行顺序问题

首先看下俩个执行后的结果,$limit在$skip前面

> db.tests.aggregate({$limit: 3},{$skip: 3},{$match: {order: {$gte: 4}}})
{ "result" : [ ], "ok" : 1 }
$limit()在$skip()的后面
> db.tests.aggregate({$skip: 3},{$limit: 3},{$match: {order: {$gte: 4}}})
{
    "result" : [
        {
            "_id" : ObjectId("5798a05d2d634aa2878ce7e4"),
            "order" : 4,
            "time" : "7-4"
        },
        {
            "_id" : ObjectId("5798a0622d634aa2878ce7e5"),
            "order" : 5,
            "time" : "7-5"
        },
        {
            "_id" : ObjectId("5798a0692d634aa2878ce7e6"),
            "order" : 6,
            "time" : "7-6"
        }
    ],
    "ok" : 1
}

通过上面的结果我们可以自己总结一下,$limit() 可以这样理解,$limit()限制的就是可以提供给后面的管道函数操作的document数目,就是说如果$limit:4也就是说执行了$limit()函数之后后面的管道函数能够操作的就是这4个document.

在这个基础上我们再来看$limit和$skip的执行顺序问题,$limit()和$skip()在一起.无论如何,$limit()都会在$skip()的前面执行,如果$limit()就在$skip()前面的话,按照上面的理解就很容易理解第一个执行的result =[];$limit()在$skip()后面的话,会被提前到$skip()前面执行,但是:

$skip的参数会被加到$limit上面,这一个机制就导致了上面俩个操作的不同的结果,所以第二个操作实际执行的是{$limit; 6},{$skip: 3},这样就简洁明了了

所以我们的优化顺序就是$limit()尽量放在$skip()的后面

扫描二维码,分享此文章

sjffly