mongoose入门

项目git地址

Mongoose学习参考文档——基础篇

MongoDB学习笔记(索引)

mongoose

mongodb

ObjectId

输出查询信息

db.tablename.find().explain( “executionStats” )

MongoDB的存储是BJSON(Binary JSON)格式,一种二进制的json格式,实际上BJSON的比json格式更大,所以mongodb是以空间换时间的;

_id和ObjectId:24个十六进制的数(12个字节):

时间戳(4个字节):保证不同秒不同;

机器id(3个字节):保证不同机器不同;

PID(2个字节):保证同一机器的多进程不同;

计数器(3个字节):保证同一秒钟产生的不同;

数据库设计优化:
    一、内嵌文档:
        1.子文档较小;
        2.数据不会定期改变;
        3.最终数据一致即可;
        4.文档数据小幅增加;
        5.数据通常需要二次查询才能获得;
        6.快速读取;

    二、引用文档:
        1.子文档较大;
        2.数据经常改变;
        3.中间数据必须一致;
        4.文档数据大幅增加;
        5.数据通常不包含在结果中;
        6.快速写入;

    三、通常把需要改变的字段放到文档的最后面;

    四、采用占位字段避免文档变大时的移动位置;

    五、采用索引优化查询速度;
    
    六、避免使用skip跳过大量数据(跳过过多数据会造成性能急剧下降);

    七、尽量使用$in代替$ne查询;
修改器操作符:
    1.普通操作符: 
        $set:{filedname:value}
        $unset: {filedname:value}
        $inc:{filedname:value}
    2.数组操作符:
        $push:
        $addToSet:
        $each:
        $slice:
        $pull:
        $pop:
        $sort:
    3.定位操作符:
        $

查询操作符:
    $gte:
    $gt:
    $lt:
    $lte:
    $or:
    $not:
    $in:
    $ne:
    $exists:
    $eq:
    $all:
    $size:
    $slice:
    $elemMatch:

聚合(aggregate)之管道操作符:
    1.普通操作符:
        $match:
            1.兼容所有常规查询操作符;
        $project:
            1.管道表达式:
                $fieldname(字段名)
            2.数学表达式:
                $add:
                $subtract:
                $multiply:
                $divide:
                $mod:
            3.日期表达式:
                $year:
                $month:
                $week:
                $dayOfMonth:
                $dayOfWeek:
                $dayOfYear:
                $hour:
                $minute:
                $second:
            4.字符串表达式:
                $substr:
                $concat:
                $toLower:
                $toUpper:
            5.逻辑表达式:
                大部分查询的比较操作符
                $cmp:
                $strcasecmp:
                $and:
                $or:
                $not:
                $cond:
                $ifNull:
        $group:
            1.算数操作符:
                $sum:
                $avg:
            2.极值操作符
                $max:
                $min:
                $first:
                $last:
            3.数组操作符:
                $addToSet:
                $push:
        $unwind:
        $sort:
        $limit:
        $skip:
    2.MapReduce

package.json

{
 "name": "mongodb",
 "version": "1.0.0",
 "description": "mongodb入门",
 "main": "index.js",
 "scripts": {
   "test": "npm run test"
 },
 "keywords": [
   "mongodb"
 ],
 "author": "vince",
 "license": "ISC",
 "dependencies": {
   "bluebird": "^3.5.1",
   "mongoose": "^4.13.9"
 }
}

model.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

module.exports = mongoose.model('test', new Schema({
    title: String,
    contents: String,
    score: {},
    attr: { type: String, default: null },
    comments: [],
    placeholder: {
        type: String, default: '...............................................' +
            '..................................................................' +
            '...................................................................'
    },
}));

class.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

module.exports = mongoose.model('class', new Schema({
    class: { type: String, unique: true },
    teacher: String,
    course: []
}));

student.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

module.exports = mongoose.model('student', new Schema({
    name: String,
    age: Number,
    hobby: [],
    class: String
}));

index.js

const Promise = require('bluebird');
const mongoose = require('mongoose');
const TestModel = require('./model');
const Class = require('./class');
const Student = require('./student');

mongoose.Promise = Promise; //引用bluebird替换mongoose的promise
mongoose.connect('mongodb://10.10.10.16:27017/test');
const connection = mongoose.connection;
connection.on('error', error => { // 数据库连接失败
    console.log('链接错误:' + error)
});

// console.log(mongoose.Types.ObjectId())
connection.once('open', () => {
    console.log('连接成功');
    return connection.dropDatabase()
        .then(data => {
            console.log('清除数据库')
            //  插入数据:create({});
            //  批量插入数据: create([{]}]) / insertMany([{}])
            return TestModel.insertMany([
                {
                    title: '标题1',
                    contents: "内容1",
                    comments: [
                        {
                            author: 'qqq1',
                            comment: '好',
                            score: 5
                        },
                        {
                            author: 'qqq2',
                            comment: '很好',
                            score: 5
                        },
                        {
                            author: 'qqq3',
                            comment: '非常好',
                            score: 5
                        }
                    ],
                    score: 15
                },
                {
                    title: '标题2',
                    contents: "内容2",
                    comments: [
                        {
                            author: 'zzz1',
                            comment: '好',
                            score: 5
                        },
                        {
                            author: 'zzz2',
                            comment: '很好',
                            score: 5
                        },
                        {
                            author: 'zzz3',
                            comment: '非常好',
                            score: 10
                        }
                    ],
                    score: 25
                },
            ])
        })
        .then(data => {
            console.log('insertMany成功:\n', data)
            //    更新数据:update();
            //    使用$push/$addToSet配合$each可以向数组中添加多个元素;$push还可以配合$slice:整数
            return TestModel.update(
                { title: '标题2' },
                {
                    $push: {
                        comments: {
                            $each: [
                                {
                                    author: 'zzz3',
                                    comment: '非常好',
                                    score: 10
                                },
                                {
                                    author: 'zzz4',
                                    comment: '非常好',
                                    score: 10
                                },
                                {
                                    author: 'zzz5',
                                    comment: '非常好',
                                    score: 10
                                }
                            ],
                            $slice: -4
                        }
                    },
                    $unset: { placeholder: 1 }
                }
            )
        })
        .then(data => {
            console.log('update/$push/$each/$slice成功:\n', data);
            //addToSet在数组中添加不重复的数值
            return TestModel.update(
                { title: '标题1' },
                {
                    $addToSet: {
                        comments: {
                            $each: [
                                {
                                    author: 'qqq4',
                                    comment: '非常好',
                                    score: 10
                                },
                                {
                                    author: 'zzz5',
                                    comment: '非常好',
                                    score: 10
                                },
                                {
                                    author: 'qqq4',
                                    comment: '非常好'
                                },
                            ],
                            $slice: -4
                        }
                    },
                    $unset: { placeholder: 1 }
                }
            )
        })
        .then(data => {
            console.log('update/$addToSet/$each成功:\n', data);
            //配合$位置修改器 更改数组中的某一个值
            return TestModel.update(
                { 'comments.author': 'zzz5', title: '标题1' },
                {
                    $set: { 'comments.$.author': 'qqq5' },
                    $unset: { placeholder: 1 }
                }
                // { multi: true }
            )
        })
        .then(data => {
            console.log('update/$成功:\n', data);
            //自增修改器$inc:{filed:整数}
            return TestModel.update(
                { title: '标题1' },
                {
                    $inc: { score: 1 },
                    $unset: { placeholder: 1 }
                }
                // ,{ multi: true } //更新多个文档
            )
        })
        .then(data => {
            console.log('update/$inc成功:\n', data);
            //update第三参数添加upsertshu属性为true,更新时,如果找不到会创建(没有默认值),否则,不会有任何更新;如果找到就是正常更新
            return TestModel.update(
                { title: '标题3' },
                {
                    contents: "内容2",
                    comments: [
                        {
                            author: 'yyy1',
                            comment: '好'
                        },
                        {
                            author: 'yyy2',
                            comment: '很好'
                        },
                        {
                            author: 'yyy3',
                            comment: '非常好'
                        }
                    ],
                },
                { upsert: true }
            )
        })
        .then(data => {
            console.log('update/upsert成功:\n', data);
            return TestModel.update(
                { title: '标题3' },
                {
                    contents: "内容3",
                    comments: [
                        {
                            author: 'yyy1',
                            comment: '好'
                        },
                        {
                            author: 'yyy2',
                            comment: '很好'
                        },
                        {
                            author: 'yyy2',
                            comment: '很好'
                        },
                        {
                            author: 'yyy2',
                            comment: '很好'
                        },
                        {
                            author: 'yyy3',
                            comment: '非常好'
                        }
                    ],
                    $set: { score: 15 },
                    $unset: { placeholder: 1 }
                },
                { upsert: 1 }
            )
        })
        .then(data => {
            console.log('update/upsert成功:\n', data);
            //使用正则表达式
            return TestModel.find(
                {
                    title: /标题2|标题3/,
                    score: { $gte: 15 }
                },
                {
                    _id: 0,
                    title: 1,
                    contents: 1,
                    comments: 1,
                    score: 1
                }
            )
        })
        .then(data => {
            console.log('reg/查找成功:\n', data);
            //$or匹配两个不同字段任意一个条件;
            return TestModel.find(
                {
                    $or: [{ title: '标题1' }, { score: { $gte: 15 } }]
                },
                {
                    _id: 0,
                    title: 1,
                    contents: 1,
                    comments: 1,
                    score: 1
                }
            )
        })
        .then(data => {
            console.log('$or查询成功:\n' + data);
            // $in 匹配同一个字段任意条件
            return TestModel.find(
                {
                    title: { $in: ['标题2', '标题3'] }
                },
                {
                    _id: 0,
                    title: 1,
                    contents: 1,
                    comments: 1,
                    score: 1
                }
            )
        })
        .then(data => {
            console.log('$in查找成功:\n' + data);
            //当返回的是model实例时;
            //保留原有的大部分API;
            //调用toString方法返回的是model._doc;
            //model.已定义字段名=值 <=> model._doc.已定义字段名=值
            //model.未定义字段名=值 <=> model.未定义字段名=值
            return TestModel.findOne(
                {
                    title: '标题3'
                },
                {
                    _id: 0,
                    title: 1,
                    contents: 1,
                    comments: 1,
                    score: 1
                }
            )
        })
        .then(data => {
            data.verify = true;
            data.score = 20;
            //调用lean()后返回值将变成普通的对象,不再拥有model的API;
            console.log('添加属性1:\n', data);
            return TestModel.findOne(
                {
                    title: '标题3'
                },
                {
                    _id: 0,
                    title: 1,
                    contents: 1,
                    comments: 1,
                    score: 1
                }
            ).lean(true)
        })
        .then(data => {
            data.verify = true;
            data.score = 20;
            console.log('添加属性2:\n', data);
            return TestModel.findOne(
                {
                    title: '标题3'
                }
            )
        })
        .then(data => {
            data._doc.verify = true;
            data.score = [5, 25];
            console.log('添加属性3:\n', data);
            // findOne如果使用了第二参数,返回的mondel保存时会报错;
            return data.save()
        })
        .then(data => {
            console.log('保存属性:\n', data);
            /*
            $where:function(){ js代码 } 
            注意事项:
                1.效率很低,, MongoDB需要把文档转成json然后执行js逻辑;
                2.外层不能使用箭头函数;不然this所指上下文会不正确;
                3.this指代的是游标当前位置的文档;
            */
            return TestModel.find(
                {
                    '$where': function () {
                        if (this.comments.length == 4) {
                            return true
                        } else {
                            return false
                        }
                    }
                }
            )
        })
        .then(data => {
            console.log('$where成功:\n', data)
            // 如果字段是一个混合类型时要注意;数组的匹配;
            // 25<?<20 理论上是匹配不到文档;
            // 实际上mongodb执行的是两个查询然后将结果取交集;
            return TestModel.find({
                score: { $gte: 25, $lte: 20 }
            })
        })
        .then(data => {
            // 示例中5<=20 && 25>=25 所以会匹配到该文档
            console.log('数组查询1:', data)
            //采用$elemMatch对数组中的每个元素进行匹配;注:只能对数组进行匹配;如果这个字段不是数组,将匹配不成功 
            return TestModel.find({ score: { $elemMatch: { $gte: 5, $lte: 20 } } }) //score:[16,18] √     score:15 ×
        })
        .then(data => {
            console.log('$elemMatch成功:\n', data)
            // return TestModel.find({}, {}, { skip: 1, limit: 2 })
            // skip进行游标操作时, 不要跳过大量的文档,这样会很慢;因为MongoDB实际上是一个一个找到后在过滤掉的;
            return TestModel.find().skip(1).limit(2)
        })
        .then(data => {
            console.log('skip/limit成功:\n', data)
            //查询值为null的字段;MongoDB中null==null为true;不存在的字段也为null;
            return TestModel.find({ attr: null })
        })
        .then(data => {
            console.log('null查询成功:\n', data)
            //查询值为null且存在时;
            return TestModel.find({ attr: { $in: [null], $exists: true } })
        })
        .then(data => {
            console.log('$exists/null查询成功:\n', data)
            //插入数据
            return TestModel.update(
                { title: '标题4' },
                {
                    contents: '内容5',
                    comments: [
                        {
                            author: 'qqq1',
                            comment: '好',
                            score: 5
                        }
                    ],
                    score: ['a', 'b', 'c']
                },
                { upsert: 1 }
            )
        })
        .then(data => {
            console.log('upsert插入成功:\n', data)
            return TestModel.create(
                {
                    title: '标题5',
                    contents: '内容5',
                    comments: [
                        {
                            author: 'qqq1',
                            comment: '好',
                            score: 5
                        }
                    ],
                    score: ['a', 'b', 'd']
                }
            )
        })
        .then(data => {
            console.log('create创建成功:\n', data)
            //针对数组查询
            //示例中的写法等价于$in;匹配时数组中有一个元素在其中,就满足条件;
            return TestModel.find({ score: ['c', 'd'] })
        })
        .then(data => {
            console.log('查询1:\n', data)
            //匹配时数组中满足两个条件才能匹配;
            return TestModel.find({ score: { $all: ['c', 'd'] } })
        })
        .then(data => {
            console.log('查询2:\n', data)
            //匹配时数组中满足两个条件才能匹配;
            return TestModel.find({ score: { $all: ['a', 'd'] } })
        })
        .then(data => {
            console.log('查询3:\n', data)
            // find的第二参数可以配合使用$slice对数组进行操作;
            // 示例:跳过前面2个取4个;
            return TestModel.findOne({ title: '标题1' }, { comments: { $slice: [2, 4] } })
        })
        .then(data => {
            console.log('查询4:\n', data)
            return TestModel.distinct('contents')
        })
        .then(data => {
            console.log('查询5:\n', data)
            //聚合:通过管道进行筛选/投射/分组/排序/限制/跳过
            //管道操作的数据保存在内存中;
            return TestModel.aggregate([
                {
                    $unwind: '$comments'
                }
            ])
        })
        .then(data => {
            console.log('管道操作1:\n', data)
            return TestModel.aggregate([
                {
                    $project: { 标题: '$title', 评论: '$comments' }
                }
            ])
        })
        .then(data => {
            console.log('管道操作2:\n', data)
            return TestModel.aggregate([
                {
                    $group: {
                        _id: '$contents',
                        标题: { $addToSet: "$title" }
                    }
                }
            ])
        })
        .then(data => {
            console.log('管道操作3:\n', data)
            return TestModel.aggregate([
                {
                    $match: {
                        title: { $in: ['标题2', '标题3', '标题4', '标题5'] }
                    }
                },
                {
                    $unwind: '$comments'
                },
                {
                    $project: {
                        标题: { $concat: ['这是标题:', { $substr: ['$title', 6, 4] }] },//$substr以字节为单位!!!
                        内容: '$contents',
                        评论: '$comments',
                        评分: { $cond: ['$comments.score', '$comments.score', 0] }
                    }
                },
                {
                    $group: {
                        _id: '$标题',
                        score: { $sum: '$评分' },
                        contents: { $addToSet: '$内容' }
                    }
                }
            ])
        })
        .then(data => {
            console.log('管道操作4:\n', data)
            return Promise.all([
                Class.insertMany([
                    {
                        class: '一年级',
                        teacher: '刘老师',
                        course: ['一年级语文', '一年级数学', '一年级自然']
                    },
                    {
                        class: '二年级',
                        teacher: '李老师',
                        course: ['二年级语文', '二年级数学', '二年级自然']
                    },
                    {
                        class: '三年级',
                        teacher: '伍老师',
                        course: ['三年级语文', '三年级数学', '三年级自然']
                    },
                ]),
                Student.insertMany([
                    {
                        name: '小花',
                        age: 6,
                        hobby: ['跳舞', '唱歌'],
                        class: '一年级'
                    },
                    {
                        name: '小明',
                        age: 7,
                        hobby: ['游泳'],
                        class: '二年级'
                    },
                ])
            ])
        })
        .then(data => {
            return Student.aggregate([
                {
                    $lookup:
                        {
                            from: "classes",
                            localField: "class",
                            foreignField: "class",
                            as: "myClass"
                        }
                }
            ])
        })
        .then(data => {
            console.log('管道操作5:\n', data)
        })
        .catch(err => {
            console.log('发生错误', err)
        })
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值