//首先基于 本 工具, 上面应选择连接, 和 对应的数据库, 以此来确认工作空间, 否则报错 , //monogodb 类似 js 的语法 //========================================= 数据库======================================================= use runoob; //创建数据库 switched to db runoob; show dbs; db.dropDatabase();//删除数据库 //========================================== 集合 ======================================================= db.createCollection("runoob"); db.createCollection("mycol", { capped:true, autoIndexId:true, size:6142800, max:10000 } ); db.mycol2.insert({"name" : "菜鸟教程"}); //插入数据自动创建集合 show collections; db.mycol2.drop(); //========================================== 插入文档 ==================================================== db.col.insert({title: 'MongoDB 教程', description: 'MongoDB 是一个 Nosql 数据库', by: '菜鸟教程', url: 'http://www.runoob.com', tags: ['mongodb', 'database', 'NoSQL'], likes: 100 }); db.col.find(); //第二种先定义变量 后 插入 document=({title: 'MongoDB 教程', description: 'MongoDB 是一个 Nosql 数据库', by: '菜鸟教程', url: 'http://www.runoob.com', tags: ['mongodb', 'database', 'NoSQL'], likes: 100 }); db.col.insert(document) WriteResult({ "nInserted" : 1 }); //3.2版本后的 语法 db.collection.insertOne({"a": 3}) ;//向指定集合中插入一条文档数据 db.collection.insertMany([{"b": 3}, {'c': 4}]);//向指定集合中插入多条文档数据 //数组插入的方式 var arr = []; for(var i=1 ; i<=20000 ; i++){ arr.push({num:i}); } db.numbers.insert(arr); //========================================== 更新文档 ============================================== //语法 db.collection.update( <query>, <update>, { upsert: <boolean>, multi: <boolean>, writeConcern: <document> } ) ; //参数说明: //query : update的查询条件,类似sql update查询内where后面的。 //update : update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的 //upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。 //multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。 //writeConcern :可选,抛出异常的级别。 db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}}) //更新一条 db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}},{multi: true}) //更新多条 WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) // 输出信息 db.col.save({ //这种方式根据 _id 判断,集合中存在则更新,否则插入 "_id" : ObjectId("56064f89ade2f21f36b03136"), "title" : "MongoDB", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "Runoob", "url" : "http://www.runoob.com", "tags" : [ "mongodb", "NoSQL" ], "likes" : 110 }); db.col.find().pretty(); //========================================== 删除文档 ================================================= //语法 db.collection.remove( <query>, { justOne: <boolean>, writeConcern: <document> } ); //参数说明: //query :(可选)删除的文档的条件。 //justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。 //writeConcern :(可选)抛出异常的级别。 db.col.remove({'title':'MongoDB 教程'}); db.col.remove({});//删除所有数据 (类似常规 SQL 的 truncate 命令): //========================================== 查询文档 =================================================== //语法 db.collection.find(query, projection); //参数说明 //query :可选,使用查询操作符指定查询条件 //projection: 可选,使用投影操作符指定返回的键。查询时返回文档中所有键值,只需省略该参数即可(默认省略)。 db.col.find().pretty();//易读的方式来显示所有文档 db.col.findOne();// db.col.find({"by":"菜鸟教程"}).pretty(); //where by = '菜鸟教程'; db.col.find({"likes":{$lt:50}}).pretty(); //where likes < 50; db.col.find({"likes":{$lte:50}}).pretty();//where likes <= 50; db.col.find({"likes":{$gt:50}}).pretty();//where likes > 50; db.col.find({"likes":{$gte:50}}).pretty();//where likes >= 50; db.col.find({"likes":{$ne:50}}).pretty();//where likes != 50; //and 语法 db.collection.find({key1:value1,key2:value2}).pretty(); db.col.find({"by":"菜鸟教程","title":"MongoDB教程"}).pretty(); //or 语法 db.col.find({$or:[{key1: value1}, {key2:value2}]}); db.col.find({$or:[{"by":"菜鸟教程"},{"title":"MongoDB教程"}]}); //and 和 or 联合使用 db.col.find({"likes":{$gt:50},$or:[{"by":'菜鸟教程'},{'title':"MongoDB 教程"}]}).pretty(); //========================================== 条件操作符 ============================================== $gt -------- greater than > $gte --------- gt equal >= $lt -------- less than < $lte --------- lt equal <= $ne ----------- not equal != $eq -------- equal = //模糊查询 其实这个里是正则方式的一种运用 db.col.find({title:/教/});//查询 title 包含"教"字的文档 db.col.find({title:/^教/});//查询 title 字段以"教"字开头的文档 db.col.find({title:/教$/});//查询 titl e字段以"教"字结尾的文档 //============多条件查询=================== db.workmate.find({$and:[{age:{$gte:30}},{"skill.skillThree":'PHP'}]}, //相当于 where age>=30 and skill.skillThree='PHP' {name:1,"skill.skillThree":1,age:1,_id:0} ) db.workmate.find({$or:[{age:{$gte:30}},{"skill.skillThree":'PHP'}]}, {name:1,"skill.skillThree":1,age:1,_id:0} ) db.workmate.find({age:{$in:[25,33]}}, {name:1,"skill.skillOne":1,age:1,_id:0} ) db.workmate.find({age:{$not:{$lte:30,$gte:20}}}, {name:1,"skill.skillOne":1,age:1,_id:0} ) //============条件操作符 $type ============ 根据类型筛选文件 //MongoDB中可以使用的类型如下表示: 类型 数字 备注 Double 1 String 2 Object 3 Array 4 Binary data 5 Undefined 6 已废弃。 Object id 7 Boolean 8 Date 9 Null 10 Regular Expression 11 JavaScript 13 Symbol 14 JavaScript (with scope) 15 32-bit integer 16 Timestamp 17 64-bit integer 18 Min key 255 Query with -1. Max key 127 //例如: 如何向获取 col 集合中title 为 String类型的数据,你可以使用以下命令: db.col.find({"title":{$type:2}}); //或 db.col.find({"title":{$type:'string'}}); //$where =================================== //$where操作符功能强大且灵活,它可以将JavaScript表达式的字符串或JavaScript函数作为查询语句的一部分。 //在JavaScri pt表达式和函数中,可以使用this或obj来引用当前操作的文档。 //JavaScript表达式或函数返回值为true时,才会返回当前的文档。 //查询时,$where操作符不能使用索引,每个文档需要从BSON对象转换成JavaSript对象后,才可以通过$where表达式来运行。 //因此,它比常规查询要慢很多,一般情况下,要避免使用$where查询。 db.getCollection('test_user').find({'$where':"function(){ return this.addresss.length>2}"}); 上述等价:db.getCollection('test_user').find({'$where':"this.addresss.length>2"}); //in 和 not in ($in $nin)=================== db.collection.find( { "field" : { $in : array } } ); //取模运算$mod==============================取模查询的列必须是数字类型的,其他类型不行,能进行取模计算的类型查询才能有作用 db.things.find( "this.a % 10 == 1") //可用$mod代替: db.things.find( { a : { $mod : [ 10 , 1 ] } } ) //$all====================================== //和$in类似,但是他需要匹配条件内所有的值: { a: [ 1, 2, 3 ] } //下面这个条件是可以匹配的: db.things.find( { a: { $all: [ 2, 3 ] } } ); //但是下面这个条件就不行了: db.things.find( { a: { $all: [ 2, 3, 4 ] } } ); //$size===================================== //是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素: //下面的语句就可以匹配: 但不能范围匹配 db.things.find( { a : { $size: 1 } } ); //$exists=================================== //$exists用来判断一个元素(字段)是否存在: db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回 db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回 //========================================== limit() 和 Skip() ============================================= //limit()语法 limit()方法接受一个数字参数,该参数指定从MongoDB中读取的记录条数。 db.COLLECTION_NAME.find().limit(NUMBER); //代表无参,只返回两条数据 的4个属性 (属性后面的值 >0 代表显示,这里因为_id 比较特殊只有这只为0才不会显示) db.col.find({},{"title":1,'by':1,'likes':1,_id:0}).limit(2) ; //Skip()语法 使用skip()方法来跳过指定数量的数据,skip方法接受一个数字参数作为跳过的记录条数,默认参数为0 db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER); //以下实例只会显示第二条文档数据 db.col.find({},{"title":1,_id:0}).limit(1).skip(1); //========================================== limit() 和 Skip() =============================================== //sort() 语法 //其中 1 为升序排列,而 -1 是用于降序排列。 db.COLLECTION_NAME.find().sort({KEY:1}) //样例:演示col集合中的数据按字段 likes的降序排序 db.col.find({},{"title":1,'likes':1,_id:0}).sort({"likes":-1}); //========================================== 索引 ============================================================= //创建索引 db.collection.createIndex(keys, options); //语法中 Key 值为你要创建的索引字段,1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可。 db.col.createIndex({'title': 1}); //升序创建 title索引 db.col.createIndex({"title":1,"description":-1});//创建多字段 复合索引 db.values.createIndex({'open': 1, 'close': 1}, {background: true});//后台创建索引,避免创建索引阻塞其他数据库操作 1、查看集合索引 db.col.getIndexes() 2、查看集合索引大小 db.col.totalIndexSize() 3、删除集合所有索引 db.col.dropIndexes() 4、删除集合指定索引 db.col.dropIndex("索引名称") 5、设置定时删除集合中的数据 //利用 TTL 集合对存储的数据进行失效时间设置:经过指定的时间段后或在指定的时间点过期,MongoDB 独立线程去清除【数据】。 5.1、设置时间180秒后自动清除。设置在创建记录后,180秒左右删除 db.col.createIndex({"createDate": 1},{expireAfterSeconds: 180}); 5.1、//设置 A 记录在 2019 年 1 月 22 日晚上 11 点左右删除, //A 记录中需添加 "ClearUpDate": new Date('Jan 22, 2019 23:00:00'),且 Index中expireAfterSeconds 设值为 0。 db.col.createIndex({"ClearUpDate": 1},{expireAfterSeconds: 0}) // 索引关键字段必须是 Date 类型。 // 非立即执行:扫描 Document 过期数据并删除是独立线程执行,默认 60s 扫描一次,删除也不一定是立即删除成 //========================================== 聚合 ============================================================= //MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果.有点类似sql语句中的 count(*) //aggregate() 方法的基本语法格式如下所示: db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION) db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}]); //$group 第一个参数_id 名为固定写法 { "result" : [ { "_id" : "runoob.com", "num_tutorial" : 2 }, { "_id" : "Neo4j", "num_tutorial" : 1 } ], "ok" : 1 } //以上实例类似sql语句: select by_user, count(*) from mycol group by by_user 下表展示了一些聚合的表达式: 表达式 描述 实例 //$sum 计算总和。 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}]) //$avg 计算平均值 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}]) //$min 获取集合中所有文档对应值得最小值。 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}]) //$max 获取集合中所有文档对应值得最大值。 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}]) //$push 在结果文档中插入值到一个数组中。 就是分组结果放在一个集合里的意思 db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}]) //$addToSet 在结果文档中插入值到一个数组中,但不创建副本。就是分组结果放在一个集合里并去重的意思 db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}]) //$first 根据资源文档的排序获取第一个文档数据。 db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}]) //$last 根据资源文档的排序获取最后一个文档数据 db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}]) // 管道的概念 =================== //管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的参数。 // //MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的。 // //表达式:处理输入文档并输出。表达式是无状态的,只能用于计算当前聚合管道的文档,不能处理其它的文档。 // //这里我们介绍一下聚合框架中常用的几个操作: // $project: 修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。 $match: 用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。 $limit: 用来限制MongoDB聚合管道返回的文档数。 $skip: 在聚合管道中跳过指定数量的文档,并返回余下的文档。 $unwind: 将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。 $group: 将集合中的文档分组,可用于统计结果。 $sort: 将输入文档排序后输出。 $geoNear: 输出接近某一地理位置的有序文档。 //管道操作符实例 1、$project实例 db.article.aggregate({ $project : { title : 1 ,author : 1 ,}}); //这样的话结果中就只含有_id,tilte和author三个字段了,默认情况下_id字段是被包含的,如果要想不包含_id话可以这样: db.article.aggregate({ $project : {_id : 0 ,title : 1 ,author : 1}}); 2.$match实例 db.articles.aggregate( [ { $match : { score : { $gt : 70, $lte : 90 } } }, { $group: { _id: null, count: { $sum: 1 } } } ] ); //$match用于获取分数大于70小于或等于90记录,然后将符合条件的记录送到下一阶段$group管道操作符进行处理。 3.$skip实例 db.article.aggregate({ $skip : 5 }); //经过$skip管道操作符处理后,前五个文档被"过滤"掉。 //===================================== 复制(副本集)其实就是主从复制,读写分离 ===================================== 自行百度 //===================================== 分片=========================================================================== 自行百度 //===================================== 备份 与 恢复 ================================================================= 1、MongoDB数据备份 mongodump命令脚本语法如下: mongodump -h dbhost -d dbname -o dbdirectory -h: //MongDB所在服务器地址,例如:127.0.0.1,当然也可以指定端口号:127.0.0.1:27017 -d: //需要备份的数据库实例,例如:test -o: //备份的数据存放位置,例如:c:\data\dump,当然该目录需要提前建立,在备份完成后,系统自动在dump目录下建立一个test目录,这个目录里面存放该数据库实例的备份数据。 实例 //在本地使用 27017 启动你的mongod服务。打开命令提示符窗口,进入MongoDB安装目录的bin目录输入命令mongodump: >mongodump //执行以上命令后,客户端会连接到ip为 127.0.0.1 端口号为 27017 的MongoDB服务上,并备份所有数据到 bin/dump/ 目录中。命令输出结果如下: mongodump 命令可选参数列表如下所示: 语法 描述 实例 mongodump --host HOST_NAME --port PORT_NUMBER 该命令将备份所有MongoDB数据 mongodump --host runoob.com --port 27017 mongodump --dbpath DB_PATH --out BACKUP_DIRECTORY mongodump --dbpath /data/db/ --out /data/backup/ mongodump --collection COLLECTION --db DB_NAME 该命令将备份指定数据库的集合。 mongodump --collection mycol --db test 2、MongoDB数据恢复 mongodb使用 mongorestore 命令来恢复备份的数据。 语法 mongorestore命令脚本语法如下: >mongorestore -h <hostname><:port> -d dbname <path> --host <:port>, -h <:port>: //MongoDB所在服务器地址,默认为: localhost:27017 --db , -d : //需要恢复的数据库实例,例如:test,当然这个名称也可以和备份时候的不一样,比如test2 --drop: //恢复的时候,先删除当前数据,然后恢复备份的数据。就是说,恢复后,备份后添加修改的数据都会被删除,慎用哦! <path>: //mongorestore 最后的一个参数,设置备份数据所在位置,例如:c:\data\dump\test。 //你不能同时指定 <path> 和 --dir 选项,--dir也可以设置备份目录。 --dir: //指定备份的目录 //你不能同时指定 <path> 和 --dir 选项。 接下来我们执行以下命令: >mongorestore //===================================== MongoDB 监控 ================================================================= mongostat 命令 //间隔固定时间获取mongodb的当前运行状态. mongotop 命令 //查看哪些大量的时间花费在读取和写入数据. 3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333 11111111111111111111111111111111111111111111-以下为高级教程-1111111111111111111111111111111111111111111111111111111 3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333 //===================================== MongoDB 关系 ================================================================= 1、首先几对几的关系都有 2、嵌入式关系 例如 地址嵌入到用户信息中 { "_id":ObjectId("52ffc33cd85242f436000001"), "contact": "987654321", "dob": "01-01-1991", "name": "Tom Benzamin", "address": [ { "building": "22 A, Indiana Apt", "pincode": 123456, "city": "Los Angeles", "state": "California" }, { "building": "170 A, Acropolis Apt", "pincode": 456789, "city": "Chicago", "state": "Illinois" }] } 3、引用式关系 通过引用文档的 id 字段来建立关系 { "_id":ObjectId("52ffc33cd85242f436000001"), "contact": "987654321", "dob": "01-01-1991", "name": "Tom Benzamin", "address_ids": [ ObjectId("52ffc4a5d85242602e000000"), ObjectId("52ffc4a5d85242602e000001") ] } //以上实例中,用户文档的 address_ids 字段包含用户地址的对象id(ObjectId)数组。 //我们可以读取这些用户地址的对象id(ObjectId)来获取用户的详细地址信息。 //这种方法需要两次查询,第一次查询用户地址的对象id(ObjectId),第二次通过查询的id获取用户的详细地址信息。 //===================================== MongoDB 数据库引用 ================================================================= MongoDB 引用有两种: 手动引用(Manual References) DBRefs DBRef的形式: { $ref : , $id : , $db : } 三个字段表示的意义为: //$ref:集合名称 //$id:引用的id //$db:数据库名称,可选参数 以下实例中用户数据文档使用了 DBRef, 字段 address: { "_id":ObjectId("53402597d852426020000002"), "address": { "$ref": "address_home", "$id": ObjectId("534009e4d852427820000002"), "$db": "runoob"}, "contact": "987654321", "dob": "01-01-1991", "name": "Tom Benzamin" } //address DBRef 字段指定了引用的地址文档是在 runoob 数据库下的 address_home 集合,id 为 534009e4d852427820000002。 //以下代码中,我们通过指定 $ref 参数(address_home 集合)来查找集合中指定id的用户地址信息: var user = db.users.findOne({"name":"Tom Benzamin"}) var dbRef = user.address db[dbRef.$ref].findOne({"_id":(dbRef.$id)}) 以上实例返回了 address_home 集合中的地址数据: { "_id" : ObjectId("534009e4d852427820000002"), "building" : "22 A, Indiana Apt", "pincode" : 123456, "city" : "Los Angeles", "state" : "California" } //===================================== MongoDB 覆盖索引查询 ============================================================ 官方的MongoDB的文档中说明,覆盖查询是以下的查询: //所有的查询字段是索引的一部分 //所有的查询返回字段在同一个索引中 //我们在 users 集合中创建联合索引,字段为 gender 和 user_name : db.users.ensureIndex({gender:1,user_name:1}) //现在,该索引会覆盖以下查询: db.users.find({gender:"M"},{user_name:1,_id:0}) //也就是说,对于上述查询,MongoDB的不会去数据库文件中查找。相反,它会从索引中提取数据,这是非常快速的数据查询。 //由于我们的索引中不包括 _id 字段,_id在查询中会默认返回,我们可以在MongoDB的查询结果集中排除它。 //下面的实例没有排除_id,查询就不会被覆盖: db.users.find({gender:"M"},{user_name:1}) //最后,如果是以下的查询,不能使用覆盖索引查询: //所有索引字段是一个数组 //所有索引字段是一个子文档 //===================================== MongoDB 查询分析 ================================================================= MongoDB 查询分析可以确保我们所建立的索引是否有效,是查询语句性能分析的重要工具。 MongoDB 查询分析常用函数有:explain() 和 hint()。 //explain 例如 db.users.find({gender:"M"},{user_name:1,_id:0}).explain();//具体参数含义自行百度 //使用 hint 来强制 MongoDB 使用一个指定的索引 //如下查询实例指定了使用 gender 和 user_name 索引字段来查询: db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1}) //===================================== MongoDB 原子性操作 ================================================================= //mongodb不支持事务,所以,在你的项目中应用时,要注意这点。无论什么设计,都不要要求mongodb保证数据的完整性。 //但是mongodb提供了许多原子操作,比如文档的保存,修改,删除等,都是原子操作。 //所谓原子操作就是要么这个文档保存到Mongodb,要么没有保存到Mongodb,不会出现查询到的文档没有保存完整的情况。 使用 db.collection.findAndModify() 方法来判断书籍是否可结算并更新新的结算信息。 book = { _id: 123456789, title: "MongoDB: The Definitive Guide", author: [ "Kristina Chodorow", "Mike Dirolf" ], published_date: ISODate("2010-09-24"), pages: 216, language: "English", publisher_id: "oreilly", available: 3, checkout: [ { by: "joe", date: ISODate("2012-10-15") } ] } db.books.findAndModify ({ query: { _id: 123456789, available: { $gt: 0 } }, update: { $inc: { available: -1 }, $push: { checkout: { by: "abc", date: new Date() } } } }) 1原子操作常用命令 $set //用来指定一个键并更新键值,若键不存在并创建。 { $set : { field : value } } $unset //用来删除一个键。 { $unset : { field : 1} } $inc //$inc可以对文档的某个值为数字型(只能为满足要求的数字)的键进行增减的操作。 { $inc : { field : value } } $push //把value追加到field里面去,field一定要是数组类型才行,如果field不存在,会新增一个数组类型加进去。 { $push : { field : value } } $pushAll//同$push,只是一次可以追加多个值到一个数组字段内。 { $pushAll : { field : value_array } } $pull //从数组field内删除一个等于value值。 { $pull : { field : _value } } $addToSet//增加一个值到数组内,而且只有当这个值不在数组内才增加。 $pop //删除数组的第一个或最后一个元素 { $pop : { field : 1 } } $rename //修改字段名称 { $rename : { old_field_name : new_field_name } } $bit //位操作,integer类型 {$bit : { field : {and : 5}}} //===================================== MongoDB 高级索引 ================================================================= { "address": { "city": "Los Angeles", "state": "California", "pincode": "123" }, "tags": [ "music", "cricket", "blogs" ], "name": "Tom Benzamin" } 1索引数组字段 //在数组中创建索引,需要对数组中的每个字段依次建立索引。 //所以在我们为数组 tags 创建索引时,会为 music、cricket、blogs三个值建立单独的索引。 //使用以下命令创建数组索引: db.users.ensureIndex({"tags":1}) //创建索引后,我们可以这样检索集合的 tags 字段: db.users.find({tags:"cricket"}) //为了验证我们使用使用了索引,可以使用 explain 命令: db.users.find({tags:"cricket"}).explain() 2索引子文档字段 //假设我们需要通过city、state、pincode字段来检索文档,由于这些字段是子文档的字段,所以我们需要对子文档建立索引。 //为子文档的三个字段创建索引,命令如下: db.users.ensureIndex({"address.city":1,"address.state":1,"address.pincode":1}) //一旦创建索引,我们可以使用子文档的字段来检索数据: db.users.find({"address.city":"Los Angeles"}) //查询表达不一定遵循指定的索引的顺序,mongodb 会自动优化。所以上面创建的索引将支持以下查询: 换句话就是不是最左原则 db.users.find({"address.state":"California","address.city":"Los Angeles"}) //同样支持以下查询: db.users.find({"address.city":"Los Angeles","address.state":"California","address.pincode":"123"}) //===================================== MongoDB 索引限制 ================================================================= 内存(RAM)使用 //由于索引是存储在内存(RAM)中,你应该确保该索引的大小不超过内存的限制。 //如果索引的大小大于内存的限制,MongoDB会删除一些索引,这将导致性能下降。 查询限制 //索引不能被以下的查询使用: //正则表达式及非操作符,如 $nin, $not, 等。 //算术运算符,如 $mod, 等。 //$where 子句 //所以,检测你的语句是否使用索引是一个好的习惯,可以用explain来查看。 索引键限制 //从2.6版本开始,如果现有的索引字段的值超过索引键的限制,MongoDB中不会创建索引。 插入文档超过索引键限制 //如果文档的索引字段值超过了索引键的限制,MongoDB不会将任何文档转换成索引的集合。与mongorestore和mongoimport工具类似。 最大范围 //集合中索引不能超过64个 //索引名的长度不能超过128个字符 //一个复合索引最多可以有31个字段 //===================================== MongoDB ObjectId ================================================================= ObjectId 是一个12字节 BSON 类型数据,有以下格式: //前4个字节表示时间戳 //接下来的3个字节是机器标识码 //紧接的两个字节由进程id组成(PID) //最后三个字节是随机数。 1创建新的ObjectId newObjectId = ObjectId(); //固有函数生成 //你也可以使用生成的id来取代MongoDB自动生成的ObjectId: myObjectId = ObjectId("5349b4ddd2781d08c09890f4"); 2创建文档的时间戳 //由于 ObjectId 中存储了 4 个字节的时间戳,所以你不需要为你的文档保存时间戳字段,你可以通过 getTimestamp 函数来获取文档的创建时间: ObjectId("5349b4ddd2781d08c09890f4").getTimestamp() 3ObjectId转换为字符串 //在某些情况下,您可能需要将ObjectId转换为字符串格式。你可以使用下面的代码: new ObjectId().str //===================================== MongoDB Map Reduce ================================================================= //Map-Reduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE)。 //MongoDB提供的Map-Reduce非常灵活,对于大规模数据分析也相当实用。 //以下是MapReduce的基本语法: >db.collection.mapReduce( function() {emit(key,value);}, //map函数 function(key,values) {return reduceFunction}, //reduce 函数 { out: collection, query: document, sort: document, limit: number } ) //Map函数调用emit(key,value)遍历一个或多个集合中所有的记录,进行分组(group by),然后将key与value传给Reduce函数进行处理,输出结果 //Map 函数必须调用 emit(key, value) 返回键值对。 1参数说明: //map :映射函数 (生成键值对序列,作为 reduce 函数参数)。 //reduce 统计函数,reduce函数的任务就是将key-values变成key-value,也就是把values数组变成一个单一的值value。。 //out 统计结果存放集合 (不指定则使用临时集合,在客户端断开后自动删除)。 //query 一个筛选条件,只有满足条件的文档才会调用map函数。(query。limit,sort可以随意组合) //sort 和limit结合的sort排序参数(也是在发往map函数前给文档排序),可以优化分组机制 //limit 发往map函数的文档数量的上限(要是没有limit,单独使用sort的用处不大) 2样例:如下 >db.posts.insert({ "post_text": "菜鸟教程,最全的技术文档。", "user_name": "mark", "status":"active" }) WriteResult({ "nInserted" : 1 }) >db.posts.insert({ "post_text": "菜鸟教程,最全的技术文档。", "user_name": "mark", "status":"active" }) WriteResult({ "nInserted" : 1 }) >db.posts.insert({ "post_text": "菜鸟教程,最全的技术文档。", "user_name": "mark", "status":"active" }) WriteResult({ "nInserted" : 1 }) >db.posts.insert({ "post_text": "菜鸟教程,最全的技术文档。", "user_name": "mark", "status":"active" }) WriteResult({ "nInserted" : 1 }) >db.posts.insert({ "post_text": "菜鸟教程,最全的技术文档。", "user_name": "mark", "status":"disabled" }) WriteResult({ "nInserted" : 1 }) >db.posts.insert({ "post_text": "菜鸟教程,最全的技术文档。", "user_name": "runoob", "status":"disabled" }) WriteResult({ "nInserted" : 1 }) >db.posts.insert({ "post_text": "菜鸟教程,最全的技术文档。", "user_name": "runoob", "status":"disabled" }) WriteResult({ "nInserted" : 1 }) >db.posts.insert({ "post_text": "菜鸟教程,最全的技术文档。", "user_name": "runoob", "status":"active" }) WriteResult({ "nInserted" : 1 }) //现在,我们将在 posts 集合中使用 mapReduce 函数来选取已发布的文章(status:"active"), //并通过user_name分组,计算每个用户的文章数: db.posts.mapReduce( function() { emit(this.user_name,1); }, function(key, values) {return Array.sum(values)}, { query:{status:"active"}, out:"post_total" } ) //以上 mapReduce 输出结果为: { "result" : "post_total", "timeMillis" : 23, "counts" : { "input" : 5, "emit" : 5, "reduce" : 1, "output" : 2 }, "ok" : 1 } //结果表明,共有 5 个符合查询条件(status:"active")的文档, //在map函数中生成了 5 个键值对文档,最后使用reduce函数将相同的键值分为 2 组。 具体参数说明: //result: 储存结果的collection的名字,这是个临时集合,MapReduce的连接关闭后自动就被删除了。 //timeMillis:执行花费的时间,毫秒为单位 //input: 满足条件被发送到map函数的文档个数 //emit: 在map函数中emit被调用的次数,也就是所有集合中的数据总量 //ouput: 结果集合中的文档个数(counts对调试非常有帮助) //ok: 是否成功,成功为1 //err: 如果失败,这里可以有失败原因,不过从经验上来看,原因比较模糊,作用不大 使用 find 操作符来查看 mapReduce 的查询结果: >db.posts.mapReduce( function() { emit(this.user_name,1); }, function(key, values) {return Array.sum(values)}, { query:{status:"active"}, out:"post_total" } ).find() 以上查询显示如下结果: { "_id" : "mark", "value" : 4 } { "_id" : "runoob", "value" : 1 } //用类似的方式,MapReduce可以被用来构建大型复杂的聚合查询。 //Map函数和Reduce函数可以使用 JavaScript 来实现,使得MapReduce的使用非常灵活和强大。 //===================================== MongoDB 全文检索 ================================================================= //全文检索对每一个词建立一个索引,指明该词在文章中出现的次数和位置, //当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。 这个过程类似于通过字典中的检索字表查字的过程。 1启用全文检索 //MongoDB 在 2.6 版本以后是默认开启全文检索的,如果你使用之前的版本,你需要使用以下代码来启用全文检索: db.adminCommand({setParameter:true,textSearchEnabled:true}) //或者使用命令: mongod --setParameter textSearchEnabled=true 2创建全文索引 //考虑以下 posts 集合的文档数据,包含了文章内容(post_text)及标签(tags): { "post_text": "enjoy the mongodb articles on Runoob", "tags": [ "mongodb", "runoob" ] } //我们可以对 post_text 字段建立全文索引,这样我们可以搜索文章内的内容: db.posts.ensureIndex({post_text:"text"}) 3使用全文索引 //现在我们已经对 post_text 建立了全文索引,我们可以搜索文章中的关键词 runoob: db.posts.find({$text:{$search:"runoob"}}) //以下命令返回了如下包含 runoob 关键词的文档数据: { "_id" : ObjectId("53493d14d852429c10000002"), "post_text" : "enjoy the mongodb articles on Runoob", "tags" : [ "mongodb", "runoob" ] } //如果你使用的是旧版本的 MongoDB,你可以使用以下命令: db.posts.runCommand("text",{search:"runoob"}) 4删除全文索引 //删除已存在的全文索引,可以使用 find 命令查找索引名: db.posts.getIndexes() //通过以上命令获取索引名,本例的索引名为post_text_text,执行以下命令来删除索引: db.posts.dropIndex("post_text_text") //===================================== MongoDB 正则表达式 ================================================================= //MongoDB 使用 $regex 操作符来设置匹配字符串的正则表达式。 //MongoDB使用PCRE (Perl Compatible Regular Expression) 作为正则表达式语言。 //不同于全文检索,我们使用正则表达式不需要做任何配置。 //考虑以下 posts 集合的文档结构,该文档包含了文章内容和标签: { "post_text": "enjoy the mongodb articles on runoob", "tags": [ "mongodb", "runoob" ] } //使用正则表达式 1以下命令使用正则表达式查找包含 runoob 字符串的文章: db.posts.find({post_text:{$regex:"runoob"}}) //以上查询也可以写为: db.posts.find({post_text:/runoob/}) 2不区分大小写的正则表达式 //如果检索需要不区分大小写,我们可以设置 $options 为 $i。 //以下命令将查找不区分大小写的字符串 runoob: db.posts.find({post_text:{$regex:"runoob",$options:"$i"}}) //集合中会返回所有包含字符串 runoob 的数据,且不区分大小写: { "_id" : ObjectId("53493d37d852429c10000004"), "post_text" : "hey! this is my post on runoob", "tags" : [ "runoob" ] } 3数组元素使用正则表达式 //我们还可以在数组字段中使用正则表达式来查找内容。 这在标签的实现上非常有用, //如果你需要查找包含以 run 开头的标签数据(ru 或 run 或 runoob), 你可以使用以下代码: db.posts.find({tags:{$regex:"run"}}) 4优化正则表达式查询 //如果你的文档中字段设置了索引,那么使用索引相比于正则表达式匹配查找所有的数据查询速度更快。 //如果正则表达式是前缀表达式,所有匹配的数据将以指定的前缀字符串为开始。 //例如: 如果正则表达式为 ^tut ,查询语句将查找以 tut 为开头的字符串。 //这里面使用正则表达式有两点需要注意: //正则表达式中使用变量。一定要使用eval将组合的字符串进行转换,不能直接将字符串拼接后传入给表达式。否则没有报错信息,只是结果为空! //实例如下: //以下是模糊查询包含title关键词, 且不区分大小写: title:eval("/"+title+"/i") // 等同于 title:{$regex:title,$Option:"$i"} //===================================== MongoDB GridFS ================================================================= //GridFS 用于存储和恢复那些超过16M(BSON文件限制)的文件(如:图片、音频、视频等)。 //GridFS 也是文件存储的一种方式,但是它是存储在MonoDB的集合中。 //GridFS 可以更好的存储大于16M的文件。 //GridFS 会将大文件对象分割成多个小的chunk(文件片段),一般为256k/个,每个chunk将作为MongoDB的一个文档(document)被存储在chunks集合中。 //GridFS 用两个集合来存储一个文件:fs.files与fs.chunks。 //每个文件的实际内容被存在chunks(二进制数据)中,和文件有关的meta数据(filename,content_type,还有用户自定义的属性)将会被存在files集合中。 //以下是简单的 fs.files 集合文档: { "filename": "test.txt", "chunkSize": NumberInt(261120), "uploadDate": ISODate("2014-04-13T11:32:33.557Z"), "md5": "7b762939321e146569b07f72c62cca4f", "length": NumberInt(646) } //以下是简单的 fs.chunks 集合文档: { "files_id": ObjectId("534a75d19f54bfec8a2fe44b"), "n": NumberInt(0), "data": "Mongo Binary Data" } //GridFS 添加文件 //现在我们使用 GridFS 的 put 命令来存储 mp3 文件。 调用 MongoDB 安装目录下bin的 mongofiles.exe工具。 //打开命令提示符,进入到MongoDB的安装目录的bin目录中,找到mongofiles.exe,并输入下面的代码: mongofiles.exe -d gridfs put song.mp3 //GridFS 是存储文件的数据名称。如果不存在该数据库,MongoDB会自动创建。Song.mp3 是音频文件名。 //使用以下命令来查看数据库中文件的文档: db.fs.files.find() //以上命令执行后返回以下文档数据: { _id: ObjectId('534a811bf8b4aa4d33fdf94d'), filename: "song.mp3", chunkSize: 261120, uploadDate: new Date(1397391643474), md5: "e4f53379c909f7bed2e9d631e15c1c41", length: 10401959 } //我们可以看到 fs.chunks 集合中所有的区块,以下我们得到了文件的 _id 值,我们可以根据这个 _id 获取区块(chunk)的数据: db.fs.chunks.find({files_id:ObjectId('534a811bf8b4aa4d33fdf94d')}) //以上实例中,查询返回了 40 个文档的数据,意味着mp3文件被存储在40个区块中。 //===================================== MongoDB 固定集合(Capped Collections) ================================================================= //MongoDB 固定集合(Capped Collections)是性能出色且有着固定大小的集合, //对于大小固定,我们可以想象其就像一个环形队列,当集合空间用完后,再插入的元素就会覆盖最初始的头部的元素! 1创建固定集合 //我们通过createCollection来创建一个固定集合,且capped选项设置为true: db.createCollection("cappedLogCollection",{capped:true,size:10000}) //还可以指定文档个数,加上max:1000属性: db.createCollection("cappedLogCollection",{capped:true,size:10000,max:1000}) 1判断集合是否为固定集合: db.cappedLogCollection.isCapped() 1如果需要将已存在的集合转换为固定集合可以使用以下命令: db.runCommand({"convertToCapped":"posts",size:10000}) //以上代码将我们已存在的 posts 集合转换为固定集合。 1固定集合查询 //固定集合文档按照插入顺序储存的,默认情况下查询就是按照插入顺序返回的,也可以使用$natural调整返回顺序。 db.cappedLogCollection.find().sort({$natural:-1}) 1固定集合的功能特点 //可以插入及更新,但更新不能超出collection的大小,否则更新失败,不允许删除,但是可以调用drop()删除集合中的所有行,但是drop后需要显式地重建集合。 //在32位机子上一个cappped collection的最大值约为482.5M,64位上只受系统文件大小的限制。 1固定集合属性及用法 属性 //属性1:对固定集合进行插入速度极快 //属性2:按照插入顺序的查询输出速度极快 //属性3:能够在插入最新数据时,淘汰最早的数据 用法 //用法1:储存日志信息 //用法2:缓存一些少量的文档 //===================================== MongoDB 自动增长(自定义自动整增长列) ================================================================= //MongoDB 没有像 SQL 一样有自动增长的功能, MongoDB 的 _id 是系统自动生成的12字节唯一标识。 //但在某些情况下,我们可能需要实现 ObjectId 自动增长功能。 //由于 MongoDB 没有实现这个功能,我们可以通过编程的方式来实现,以下我们将在 counters 集合中实现_id字段自动增长。 1使用counters集合 //考虑以下 products 文档。我们希望 _id 字段实现 从 1,2,3,4 到 n 的自动增长功能。 { "_id":1, "product_name": "Apple iPhone", "category": "mobiles" } //为此,创建 counters 集合,序列字段值可以实现自动长: db.createCollection("counters"); //现在我们向 counters 集合中插入以下文档,使用 productid 作为 key: //sequence_value 字段是序列通过自动增长后的一个值。 //使用以下命令插入 counters 集合的序列文档中: db.counters.insert({_id:"productid",sequence_value:0}); 2创建Javascript函数 //现在,我们创建函数 getNextSequenceValue 来作为序列名的输入, //指定的序列会自动增长 1 并返回最新序列值。在本文的实例中序列名为 productid 。 function getNextSequenceValue(sequenceName){ var sequenceDocument = db.counters.findAndModify( { query:{_id: sequenceName }, update: {$inc:{sequence_value:1}}, "new":true }); return sequenceDocument.sequence_value; } 3使用Javascript函数 //接下来我们将使用 getNextSequenceValue 函数创建一个新的文档, 并设置文档 _id 自动为返回的序列值: db.products.insert({ "_id":getNextSequenceValue("productid"), "product_name":"Apple iPhone", "category":"mobiles"}); db.products.insert({ "_id":getNextSequenceValue("productid"), "product_name":"Samsung S3", "category":"mobiles"}); //就如你所看到的,我们使用 getNextSequenceValue 函数来设置 _id 字段。 //为了验证函数是否有效,我们可以使用以下命令读取文档: db.products.find();