1. 程式人生 > >MongoDB高階查詢用法

MongoDB高階查詢用法

db的幫助文件

輸入:db.help();

db.AddUser(username,password[, readOnly=false])  新增使用者  

db.auth(usrename,password)     設定資料庫連線驗證  

db.cloneDataBase(fromhost)     從目標伺服器克隆一個數據庫  

db.commandHelp(name)           returns the help for the command  

db.copyDatabase(fromdb,todb,fromhost)  複製資料庫fromdb---源資料庫名稱,todb---目標資料庫名稱,fromhost---源資料庫伺服器地址  

db.createCollection(name,{size:3333,capped:333,max:88888})  建立一個數據集,相當於一個表  

db.currentOp()                 取消當前庫的當前操作  

db.dropDataBase()              刪除當前資料庫  

db.eval(func,args)             run code server-side  

db.getCollection(cname)        取得一個數據集合,同用法:db['cname'] or  

db.getCollenctionNames()       取得所有資料集合的名稱列表  

db.getLastError()              返回最後一個錯誤的提示訊息  

db.getLastErrorObj()           返回最後一個錯誤的物件  

db.getMongo()                  取得當前伺服器的連線物件get the server  

db.getMondo().setSlaveOk()     allow this connection to read from then nonmaster membr of a replica pair  

db.getName()                   返回當操作資料庫的名稱  

db.getPrevError()              返回上一個錯誤物件  

db.getProfilingLevel()         獲取profile level  

db.getReplicationInfo()        獲得重複的資料  

db.getSisterDB(name)           get the db at the same server as this onew  

db.killOp()                    停止(殺死)在當前庫的當前操作  

db.printCollectionStats()      返回當前庫的資料集狀態  

db.printReplicationInfo()        列印主資料庫的複製狀態資訊  

db.printSlaveReplicationInfo()        列印從資料庫的複製狀態資訊  

db.printShardingStatus()       返回當前資料庫是否為共享資料庫  

db.removeUser(username)        刪除使用者  

db.repairDatabase()            修復當前資料庫  

db.resetError()  

db.runCommand(cmdObj)          run a database command. if cmdObj is a string, turns it into {cmdObj:1}  

db.setProfilingLevel(level)    設定profile level 0=off,1=slow,2=all  

db.shutdownServer()            關閉當前服務程式  

db.stats()                       返回當前資料庫的狀態資訊

db.version()                   返回當前程式的版本資訊

表的幫助,格式:db.表名.help()

db.test.find({id:10})          返回test資料集ID=10的資料集  

db.test.find({id:10}).count()  返回test資料集ID=10的資料總數  

db.test.find({id:10}).limit(2) 返回test資料集ID=10的資料集從第二條開始的資料集  

db.test.find({id:10}).skip(8)  返回test資料集ID=10的資料集從0到第八條的資料集  

db.test.find({id:10}).limit(2).skip(8)  返回test資料集ID=1=的資料集從第二條到第八條的資料  

db.test.find({id:10}).sort()   返回test資料集ID=10的排序資料集  

db.test.findOne([query])       返回符合條件的一條資料  

db.test.getDB()                返回此資料集所屬的資料庫名稱  

db.test.getIndexes()           返回些資料集的索引資訊  

db.test.group({key:...,initial:...,reduce:...[,cond:...]})    返回分組資訊  

db.test.mapReduce(mayFunction,reduceFunction,<optional params>)  這個有點像儲存過程  

db.test.remove(query)                      在資料集中刪除一條資料  

db.test.renameCollection(newName)          重新命名些資料集名稱  

db.test.save(obj)                          往資料集中插入一條資料  

db.test.stats()                            返回此資料集的狀態  

db.test.storageSize()                      返回此資料集的儲存大小  

db.test.totalIndexSize()                   返回此資料集的索引檔案大小  

db.test.totalSize()                        返回些資料集的總大小  

db.test.update(query,object[,upsert_bool]) 在此資料集中更新一條資料  

db.test.validate()                         驗證此資料集  

db.test.getShardVersion()                  返回資料集共享版本號  

版本一:

1 ) . 大於,小於,大於或等於,小於或等於

$gt:大於
$lt:小於
$gte:大於或等於
$lte:小於或等於

例子:

db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value
db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value
db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value

如查詢j大於3,小於4:

db.things.find({j : {$lt: 3}});
db.things.find({j : {$gte: 4}});

也可以合併在一條語句內:

db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value

2) 不等於 $ne

例子:

db.things.find( { x : { $ne : 3 } } );

3) in 和 not in ($in $nin)

語法:

db.collection.find( { "field" : { $in : array } } );

例子:

db.things.find({j:{$in: [2,4,6]}});
db.things.find({j:{$nin: [2,4,6]}});


4) 取模運算$mod

如下面的運算:

db.things.find( "this.a % 10 == 1")

可用$mod代替:

db.things.find( { a : { $mod : [ 10 , 1 ] } } )


5)  $all

$all和$in類似,但是他需要匹配條件內所有的值:

如有一個物件:

{ a: [ 1, 2, 3 ] }

下面這個條件是可以匹配的:

db.things.find( { a: { $all: [ 2, 3 ] } } );

但是下面這個條件就不行了:

db.things.find( { a: { $all: [ 2, 3, 4 ] } } );


6)  $size

$size是匹配陣列內的元素數量的,如有一個物件:{a:["foo"]},他只有一個元素:

下面的語句就可以匹配:

db.things.find( { a : { $size: 1 } } );

官網上說不能用來匹配一個範圍內的元素,如果想找$size<5之類的,他們建議建立一個欄位來儲存元素的數量。

You cannot use $size to find a range of sizes (for example: arrays with more than 1 element). If you need to query for a range, create an extra size field that you increment when you add elements.

7)$exists

$exists用來判斷一個元素是否存在:

如:

db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回
db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回

8)  $type

$type 基於 bson type來匹配一個元素的型別,像是按照型別ID來匹配,不過我沒找到bson型別和id對照表。

db.things.find( { a : { $type : 2 } } ); // matches if a is a string
db.things.find( { a : { $type : 16 } } ); // matches if a is an int

9)正則表示式

mongo支援正則表示式,如:

db.customers.find( { name : /acme.*corp/i } ); // 後面的i的意思是區分大小寫

10)  查詢資料內的值

下面的查詢是查詢colors內red的記錄,如果colors元素是一個數據,資料庫將遍歷這個陣列的元素來查詢。

db.things.find( { colors : "red" } );

11) $elemMatch

如果物件有一個元素是陣列,那麼$elemMatch可以匹配內陣列內的元素:

> t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } ) 
{ "_id" : ObjectId("4b5783300334000000000aa9"),  
"x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
}
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的條件都要匹配上才行。

注意,上面的語句和下面是不一樣的。

> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )

$elemMatch是匹配{ "a" : 1, "b" : 3 },而後面一句是匹配{ "b" : 99 }, { "a" : 11 } 

12)  查詢嵌入物件的值

db.postings.find( { "author.name" : "joe" } );

注意用法是author.name,用一個點就行了。更詳細的可以看這個連結: dot notation

舉個例子:

> db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})

如果我們要查詢 authors name 是Jane的, 我們可以這樣:

> db.blog.findOne({"author.name" : "Jane"})

如果不用點,那就需要用下面這句才能匹配:

db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})

下面這句:

db.blog.findOne({"author" : {"name" : "Jane"}})

是不能匹配的,因為mongodb對於子物件,他是精確匹配。

13) 元操作符 $not 取反

如:

db.customers.find( { name : { $not : /acme.*corp/i } } );
db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );

shell 環境下的操作:

   1.  超級使用者相關:

         1. #進入資料庫admin

             use admin

         2. #增加或修改使用者密碼

          db.addUser('name','pwd')

         3. #檢視使用者列表

          db.system.users.find()

         4. #使用者認證

          db.auth('name','pwd')

         5. #刪除使用者

          db.removeUser('name')

         6. #檢視所有使用者

          show users

         7. #檢視所有資料庫

          show dbs

         8. #檢視所有的collection

          show collections

         9. #檢視各collection的狀態

          db.printCollectionStats()

        10. #檢視主從複製狀態

          db.printReplicationInfo()

        11. #修復資料庫

          db.repairDatabase()

        12. #設定記錄profiling,0=off 1=slow 2=all

          db.setProfilingLevel(1)

        13. #檢視profiling

          show profile

        14. #拷貝資料庫

          db.copyDatabase('mail_addr','mail_addr_tmp')

        15. #刪除collection

          db.mail_addr.drop()

        16. #刪除當前的資料庫

          db.dropDatabase()

   2. 增刪改

         1. #儲存巢狀的物件

             db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})

         2. #儲存陣列物件

             db.user_addr.save({'Uid':'[email protected]','Al':['[email protected]','[email protected]']})

         3. #根據query條件修改,如果不存在則插入,允許修改多條記錄

            db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)

         4. #刪除yy=5的記錄

            db.foo.remove({'yy':5})

         5. #刪除所有的記錄

            db.foo.remove()

   3. 索引

         1. #增加索引:1(ascending),-1(descending)

         2. db.foo.ensureIndex({firstname: 1, lastname: 1}, {unique: true});

         3. #索引子物件

         4. db.user_addr.ensureIndex({'Al.Em': 1})

         5. #檢視索引資訊

         6. db.foo.getIndexes()

         7. db.foo.getIndexKeys()

         8. #根據索引名刪除索引

         9. db.user_addr.dropIndex('Al.Em_1')

   4. 查詢

         1. #查詢所有

        2. db.foo.find()

        3. #查詢一條記錄

        4. db.foo.findOne()

        5. #根據條件檢索10條記錄

        6. db.foo.find({'msg':'Hello 1'}).limit(10)

        7. #sort排序

        8. db.deliver_status.find({'From':'[email protected]'}).sort({'Dt',-1})

         9. db.deliver_status.find().sort({'Ct':-1}).limit(1)

        10. #count操作

        11. db.user_addr.count()

        12. #distinct操作,查詢指定列,去重複

        13. db.foo.distinct('msg')

        14. #”>=”操作

        15. db.foo.find({"timestamp": {"$gte" : 2}})

        16. #子物件的查詢

        17. db.foo.find({'address.city':'beijing'})

   5. 管理

         1. #檢視collection資料的大小

         2. db.deliver_status.dataSize()

         3. #檢視colleciont狀態

         4. db.deliver_status.stats()

         5. #查詢所有索引的大小

         6. db.deliver_status.totalIndexSize()

6.  高階查詢

條件操作符 
$gt : > 
$lt : < 
$gte: >= 
$lte: <= 
$ne : !=、<> 
$in : in 
$nin: not in 
$all: all 
$not: 反匹配(1.3.3及以上版本) 

查詢 name <> "bruce" and age >= 18 的資料 
db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}}); 

查詢 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的資料 
db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)}); 

查詢 age in (20,22,24,26) 的資料 
db.users.find({age: {$in: [20,22,24,26]}}); 

查詢 age取模10等於0 的資料 
db.users.find('this.age % 10 == 0'); 
或者 
db.users.find({age : {$mod : [10, 0]}}); 

匹配所有 
db.users.find({favorite_number : {$all : [6, 8]}}); 
可以查詢出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] } 
可以不查詢出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } 

查詢不匹配name=B*帶頭的記錄 
db.users.find({name: {$not: /^B.*/}}); 
查詢 age取模10不等於0 的資料 
db.users.find({age : {$not: {$mod : [10, 0]}}}); 

#返回部分欄位 
選擇返回age和_id欄位(_id欄位總是會被返回) 
db.users.find({}, {age:1}); 
db.users.find({}, {age:3}); 
db.users.find({}, {age:true}); 
db.users.find({ name : "bruce" }, {age:1}); 
0為false, 非0為true 

選擇返回age、address和_id欄位 
db.users.find({ name : "bruce" }, {age:1, address:1}); 

排除返回age、address和_id欄位 
db.users.find({}, {age:0, address:false}); 
db.users.find({ name : "bruce" }, {age:0, address:false}); 

陣列元素個數判斷 
對於{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }記錄 
匹配db.users.find({favorite_number: {$size: 3}}); 
不匹配db.users.find({favorite_number: {$size: 2}}); 

$exists判斷欄位是否存在 
查詢所有存在name欄位的記錄 
db.users.find({name: {$exists: true}}); 
查詢所有不存在phone欄位的記錄 
db.users.find({phone: {$exists: false}}); 

$type判斷欄位型別 
查詢所有name欄位是字元型別的 
db.users.find({name: {$type: 2}}); 
查詢所有age欄位是整型的 
db.users.find({age: {$type: 16}}); 

對於字元欄位,可以使用正則表示式 
查詢以字母b或者B帶頭的所有記錄 
db.users.find({name: /^b.*/i}); 

$elemMatch(1.3.1及以上版本) 
為陣列的欄位中匹配其中某個元素 

Javascript查詢和$where查詢 
查詢 age > 18 的記錄,以下查詢都一樣 
db.users.find({age: {$gt: 18}}); 
db.users.find({$where: "this.age > 18"}); 
db.users.find("this.age > 18"); 
f = function() {return this.age > 18} db.users.find(f); 

排序sort() 
以年齡升序asc 
db.users.find().sort({age: 1}); 
以年齡降序desc 
db.users.find().sort({age: -1}); 

限制返回記錄數量limit() 
返回5條記錄 
db.users.find().limit(5); 
返回3條記錄並列印資訊 
db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); 
結果 
my age is 18 
my age is 19 
my age is 20 

限制返回記錄的開始點skip() 
從第3條記錄開始,返回5條記錄(limit 3, 5) 
db.users.find().skip(3).limit(5); 

查詢記錄條數count() 
db.users.find().count(); 
db.users.find({age:18}).count(); 
以下返回的不是5,而是user表中所有的記錄數量 
db.users.find().skip(10).limit(5).count(); 
如果要返回限制之後的記錄數量,要使用count(true)或者count(非0) 
db.users.find().skip(10).limit(5).count(true); 

分組group() 
假設test表只有以下一條資料 
{ domain: "www.mongodb.org" 
, invoked_at: {d:"2009-11-03", t:"17:14:05"} 
, response_time: 0.05 
, http_action: "GET /display/DOCS/Aggregation" 

使用group統計test表11月份的資料count:count(*)、total_time:sum(response_time)、avg_time:total_time/count; 
db.test.group( 
{ cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}} 
, key: {http_action: true} 
, initial: {count: 0, total_time:0} 
, reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time } 
, finalize: function(out){ out.avg_time = out.total_time / out.count } 
} ); 



"http_action" : "GET /display/DOCS/Aggregation", 
"count" : 1, 
"total_time" : 0.05, 
"avg_time" : 0.05 

]

MongoDB 高階聚合查詢

MongoDB版本為:2.0.8 

系統為:64位Ubuntu 12.04

先給他家看一下我的表結構[Oh sorry, Mongo叫集合]

MongoDB 高階聚合查詢

如你所見,我儘量的模擬現實生活中的場景。這是一個人的實體,他有基本的manId, manName, 有朋友[myFriends],有喜歡的水果[fruits],而且每種水果都有喜歡的權重。

很不好的是你還看見了有個“_class”欄位? 因為我是Java開發者, 我還喜歡用Spring,因此我選用了Spring Data Mongo的類庫[也算是框架吧,但是我不這麼覺得]。

現在有很多人Spring見的膩了也開始煩了。是的,Spring野心很大,他幾乎想要壟斷Java方面的任何事情。沒辦法我從使用Spring後就離不開他,以至於其他框架基本上都不用學。我學了Spring的很多,諸如:Spring Security/Spring Integration/Spring Batch等。。。不發明輪子的他已經提供了程式設計裡的很多場景,我利用那些場景解決了工作中的很多問題,也使我的工作變得很高效。從而我又時間學到它更多。Spring Data Mongo封裝了mongodb java driver,提供了和SpringJDBC/Template一致程式設計風格的MongoTemplate。

不說廢話了,我們直接來MongoDB吧。

  • Max 和Min

我和同事在測試Mongo時,索引還寫了不到一半,他想查詢某個欄位的最大值,結果找了半天文件也沒找到關於max的函式。我也很納悶這是常規函式啊怎麼不提供? 後來經過翻閱資料確定Mongo確實不提供直接的max和min函式。但是可以通過間接的方式[sort 和 limit]實現這個。

要查詢最大值我們只需要把結果集按照降序排列,取第一個值就是了。

如我的例子,我想取得集合中年齡最大的人。

1 db.person.find({}).sort({"age" : -1}).limit(1)

相反如果想要年齡最小的人,只需要把sort中改為{“age”:1}就可以了。

當然我們使用了sort,對於小數量的文件是沒問題的。當對於大量資料需要給age建立索引,否則這個操作很耗時。

  • distinct

MongoDB的destinct命令是獲取特定欄位中不同值列表的最簡單工具。該命令適用於普通欄位,陣列欄位[myFriends]和陣列內嵌文件[fruits].

如上面的圖片,我認為fruits和myFriends欄位是不同的。網上很多資料和例子都沒說到這個情景,因為我們也業務是fruits這樣的模型,我測試了。對於fruits.fruitId他也是可行的。

如上面的表結構,我想統計所有的喜歡的水果。

1

db.person.distinct("fruits.fruitId"// 查詢物件裡引入物件的值,直接加.

 他成功執行了。輸出如:

1

"aaa""bbb""ccc""www""xxx""yyy""zzz""rrr" ]

 我想統計集合中共有多少個人[按名字吧]

1

db.person.distinct("manName")

 我想統計指定個數的人的共同關注的朋友。

1

db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin""YangYan"]}})

 輸出如:

1

"234567""345678""456789""987654""ni""wo" ]