mongo查詢操作符

一 ?基本概念

MongoDB中數(shù)據(jù)的結(jié)構(gòu)為:庫、集合、文檔

1 數(shù)據(jù)庫

多個集合可以組成數(shù)據(jù)庫。MongoDb的單個實例可以容納多個獨立的數(shù)據(jù)庫,每個都有自己的集合和權(quán)限,不同的數(shù)據(jù)庫也放置在不同的文件中。

數(shù)據(jù)庫通過名字來標(biāo)識,庫名可以是滿足以下條件的任意UTF-8字符串:

不能是空字符串("")。

不得含有' '(空格)、.、$、/、\和\0 (空宇符)。

應(yīng)全部小寫。

最多64字節(jié)。

Mongo保留庫

admin:從權(quán)限角度看,這是“root”數(shù)據(jù)庫。要是將一個用戶添加到這個數(shù)據(jù)庫,這個用戶自動繼承所有數(shù)據(jù)庫的權(quán)限。一些特定的服務(wù)端命令也只能從這個數(shù)據(jù)庫運行,比如關(guān)閉數(shù)據(jù)庫。

local:這個數(shù)據(jù)庫不會被復(fù)制。可以用來存儲限于需要儲存在本地單臺服務(wù)器的集合

config:當(dāng)Mongo用于分片設(shè)置時,config數(shù)據(jù)庫在內(nèi)部使用,用于保存分片的信息。

2 集合

集合容納文檔,沒有模式。比起關(guān)系型數(shù)據(jù)庫,集合可以存放任意文檔。但把各種文檔放進一個集合在管理和效率是都不是好的方式,推薦用關(guān)系型數(shù)據(jù)庫的思維來管理文檔結(jié)構(gòu)。

集合通過名字來標(biāo)識,集合名可以是滿足以下條件的任意UTF-8字符串:

集合名不能是空字符串""。

集合名不能含有\(zhòng)0字符(空字符),這個字符表示集合名的結(jié)尾。

集合名不能以"system."開頭,這是為系統(tǒng)集合保留的前綴。

用戶創(chuàng)建的集合名字不能含有保留字符。有些驅(qū)動程序的確支持在集合名里面包含,這是因為某些系統(tǒng)生成的集合中包含該字符。除非你要訪問這種系統(tǒng)創(chuàng)建的集合,否則千萬不要在名字里出現(xiàn)$。

3 文檔

文檔是MongoDB中數(shù)據(jù)的基本單元(類似于關(guān)系型數(shù)據(jù)庫中的行)。多個鍵及其關(guān)鍵的值有序的放置在一起便是文檔。MongoDB的文件儲存格式為BSON。

示例:{"name":"dongbo","age":"100"}

注意:

文檔一定是用“{}”括起來

文檔的鍵是雙引號括起來的字符串,不能重復(fù)

不能含有\(zhòng)0 (空字符)。這個字符用來表示鍵的結(jié)尾。

.和$有特別的意義,只有在特定環(huán)境下才能使用。

以下劃線"_"開頭的鍵是保留的(不是嚴(yán)格要求的)。

文檔的值可以是字符串、數(shù)字、數(shù)組、文檔等mongo支持的數(shù)據(jù)類型。字符串需用雙引號括起來。

MongoDB區(qū)分類型和大小寫

鍵值對是有序的。

二 查詢

find函數(shù)查詢集合中所有符合查詢條件的文檔并返回結(jié)果為游標(biāo)的文檔集合。findOne查詢一個符合查詢條件的文檔。

在mongo shell中我們不需要JavaScript游標(biāo)處理方法就可以直接訪問作為查詢結(jié)果的文檔集合。當(dāng)執(zhí)行查詢操作時,mongo shell直接自動的對游標(biāo)執(zhí)行迭代操作并顯示前20條文檔,輸入"it"顯示接下來的20條文檔。

設(shè)置顯示文檔數(shù):DBQuery.shellBatchSize=50,設(shè)置完后執(zhí)行find函數(shù)就能顯示出前50條文檔記錄。

如果我們通過變量保存find返回的游標(biāo),其不會自動進行遍歷:

var cursor = db.inventory.find()

實際發(fā)生的是,調(diào)用find后,此時并不會真正的訪問數(shù)據(jù)庫,而是等待開始要求獲取結(jié)果的時候才向數(shù)據(jù)庫發(fā)送查詢請求。當(dāng)調(diào)用hasNext或者next方法時才會真正訪問數(shù)據(jù)庫,這就是懶加載的過程。

先插入一些數(shù)據(jù):

db.inventory.insert({"name":"t1","amount":16,"tags":["apple", "banana"]})

db.inventory.insert({"name":"t2","amount":50,"tags":["banana", "orange"]})

db.inventory.insert({"name":"t3","amount":58,"tags":["orange", "apple"]})

1 游標(biāo)操作

處理游標(biāo)有三個函數(shù):limit、skip、sort。limit用來限制返回的文檔數(shù)量,skip用來指定忽略前面的n條文檔,sort用來對文檔進行排序。三個函數(shù)有優(yōu)先級關(guān)系:先sort排序,然后skip跳過前面n個值,最后limit限制文檔最大返回數(shù)量。

db.inventory.find({"amount":{$lt:60}}).sort({"amount":1}).skip(1).limit(2)

{ "_id" :ObjectId("55a13b26b26f97b960389a5e"), "name" :"t2", "amount" : 50, "tags" : ["banana", "orange" ] }

{ "_id" :ObjectId("55a13b27b26f97b960389a5f"), "name" :"t3", "amount" : 58, "tags" : ["orange", "apple" ] }

示例中操作語句的寫法只是示意優(yōu)先級關(guān)系,返回結(jié)果跟3個函數(shù)的書寫順序無關(guān)。

示例中按照amount排序,因為amount的值都是整數(shù),所以排序依據(jù)數(shù)字的大小而來。然而Mongo中對鍵并不會強制要求是什么類型,一個集合中多個文檔的某一個鍵對應(yīng)的值可能是mongodb支持的不同類型,應(yīng)對這種情況,MongoDb預(yù)先定義了一個順序,從小到大依次為:

(1):最小值

(2):null

(3):數(shù)字(整型,長整型,雙精度)

(4):字符串

(5):對象/文檔

(6):數(shù)組

(7):二進制數(shù)據(jù)

(8):對象ID

(9):布爾值

(10):日期型

(11):時間戳

(12):正則表達式

(13):最大值

按照這個順序,便可以跨類型排序。

排序示例:

db.inventory.find().sort({"amount":-1})

{ "_id" :ObjectId("55a13b27b26f97b960389a5f"), "name" :"t3", "amount" : 58, "tags" : ["orange", "apple" ] }

{ "_id" :ObjectId("55a13b26b26f97b960389a5e"), "name" :"t2", "amount" : 50, "tags" : ["banana", "orange" ] }

{ "_id" :ObjectId("55a13b26b26f97b960389a5d"), "name" :"t1", "amount" : 16, "tags" : ["apple", "banana" ] }

限制文檔行數(shù)示例:

db.inventory.find().limit(2)

{ "_id" :ObjectId("55a13b26b26f97b960389a5d"), "name" :"t1", "amount" : 16, "tags" : ["apple", "banana" ] }

{ "_id" :ObjectId("55a13b26b26f97b960389a5e"), "name" :"t2", "amount" : 50, "tags" : ["banana", "orange" ] }

2 包裝

包裝查詢會用到一些額外的鍵:

$query

$orderby

$maxscan : integer指定查詢時最多掃描文檔的數(shù)量

$min : document查詢的開始條件

$max : document查詢的結(jié)束條件

$hint : document指定服務(wù)器使用哪些索引進行查詢

$explain : boolean獲取查詢細(xì)節(jié),如用到的索引,結(jié)果數(shù)量,耗時等,類似于關(guān)系數(shù)據(jù)庫這邊查看執(zhí)行計劃。并不會真正執(zhí)行查詢

$snapshot:boolean確保查詢的結(jié)果是在查詢執(zhí)行那一刻的一致快照。

示例:

db.inventory.find({$query:{amount:{$lt:58}},$orderby:{amount:-1},$hint:{"name":1}},{"_id":0})

{ "name" :"t1", "amount" : 16, "tags" : ["apple", "banana" ] }

{ "name" :"t2", "amount" : 50, "tags" : ["banana", "orange" ] }

3 查詢指定的鍵

示例:

db.inventory.find({},{"_id":0,"name":1,"tags":1})

{ "name" :"t1", "tags" : [ "apple", "banana" ] }

{ "name" :"t2", "tags" : [ "banana", "orange" ] }

{ "name" :"t3", "tags" : [ "orange", "apple" ] }

db.inventory.find({"amount":{$eq:50}},{"_id":0,"name":1,"tags":1})

{ "name" :"t2", "tags" : [ "banana", "orange" ] }

“0”表示不顯示,“1”表示顯示

4 使用正則表達式

示例:

db.inventory.find({"name":/1/},{"_id":0,"name":1,"tags":1})

{ "name" :"t1", "tags" : [ "apple", "banana" ] }

返回name中匹配“1”的結(jié)果

5 去除重復(fù)

示例:

db.inventory.distinct("name")

[ "t1","t2", "t3" ]

去重的作用是對某個鍵查詢的結(jié)果除去重復(fù)結(jié)果,關(guān)系型數(shù)據(jù)庫中distinct的作用也一樣

6 查詢集合中總文檔數(shù):

db.inventory.count()

7 查詢內(nèi)嵌文檔:

查詢文檔有兩種方式,一種是完全匹查詢,另一種是針對鍵/值對查詢。

db.profile.insert({"name" : [{"first" : "db", "last":"z"}]})

db.profile.insert({"name" : [{"first" : "bing", "last" : "pan" }]})

db.profile.insert({"name" : [{"first" : "bol", "last" : "z" }]})

內(nèi)嵌文檔的完全匹配查詢和數(shù)組的完全匹配查詢一樣,內(nèi)嵌文檔內(nèi)鍵值對的數(shù)量,順序都必須一致才會匹配:

db.profile.find({"name.first":"bol"})

{ "_id" :ObjectId("55a15e53b26f97b960389a6c"), "name" : [ {"first" : "bol", "last" : "z" } ] }

采用針對鍵/值對查詢,通過點來精確表示內(nèi)嵌文檔的鍵。當(dāng)內(nèi)嵌文檔變得復(fù)雜后,如鍵的值為內(nèi)嵌文檔的數(shù)組,內(nèi)嵌文檔的匹配需要些許技巧,例如使用$elemMatch操作符。

db.profile.find({"name":{$elemMatch:{"first":"bing","last":"pan"}}})

{ "_id" :ObjectId("55a15e53b26f97b960389a6b"), "name" : [ {"first" : "bing", "last" : "pan" } ] }

elemMatch投影操作符將限制查詢返回的數(shù)組字段的內(nèi)容只包含匹配elemMatch條件的數(shù)組元素。

注意:

數(shù)組中元素是內(nèi)嵌文檔。

如果多個元素匹配$elemMatch條件,操作符返回數(shù)組中第一個匹配條件的元素。

8 控制查詢返回的數(shù)組中元素的個數(shù)

使用$slice操作符,$slice:1的意思是返回數(shù)組值中前1個元素

db.inventory.find({amount:{$gt:50}},{"_id":0})

{ "name" :"t3", "amount" : 58, "tags" : ["orange", "apple" ] }

db.inventory.find({amount:{$gt:50}},{tags:{$slice:1},"_id":0})

{ "name" :"t3", "amount" : 58, "tags" : ["orange" ] }

$slice:[1,1],第一個1表示在數(shù)組中跳過的項目數(shù),第二個值表示返回的項目數(shù)。

db.inventory.find({amount:{$gt:50}},{tags:{$slice:[1,1]},"_id":0})

{ "name" :"t3", "amount" : 58, "tags" : [ "apple"] }

9 查詢操作符:

數(shù)組查詢操作符:

$all

用法:{ field : {$all:[value1,value2]}},查詢數(shù)組中包含指定值的文檔,條件的數(shù)組是文檔中已有數(shù)組的子集

示例:

db.inventory.find({"tags":{$all:["apple"]}},{"_id":0})

{ "name" :"t1", "amount" : 16, "tags" : ["apple", "banana" ] }

{ "name" :"t3", "amount" : 58, "tags" : ["orange", "apple" ] }

當(dāng)只需要匹配數(shù)組的一個值時,簡便寫法:

db.inventory.find({"tags":"apple"},{"_id":0})

{ "name" :"t1", "amount" : 16, "tags" : ["apple", "banana" ] }

{ "name" :"t3", "amount" : 58, "tags" : ["orange", "apple" ] }

$size

用法:{ field:{ $size:size } },查詢數(shù)組中元素的數(shù)量等于size的文檔,size必須是數(shù)字

示例:

db.inventory.find({"tags":{$size:2}},{"_id":0})

{ "name" :"t1", "amount" : 16, "tags" : ["apple", "banana" ] }

{ "name" :"t2", "amount" : 50, "tags" : ["banana", "orange" ] }

{ "name" :"t3", "amount" : 58, "tags" : ["orange", "apple" ] }

$elemMatch

用法:{field:{$elemMatch:{exp}}} ,文檔內(nèi)部存在由文檔作為元素組成數(shù)組,如果要以數(shù)組中的文檔作為查詢條件,就可以用$elemMatch操作符指向內(nèi)部文檔。

算術(shù)操作符

$gt

用法:{ field : { $gt:value } },查詢鍵值大于指定值的所有文檔

示例:

db.inventory.find({"amount":{$gt:50}},{"_id":0})

{ "name" :"t3", "amount" : 58, "tags" : ["orange", "apple" ] }

$gte

用法:{ field: { $gte: value } },查詢鍵值不小于指定值的所有文檔。

$lt

用法:{ field: { $lt: value } },查詢鍵值小于指定值的所有文檔。

$lte

用法:{ field: { $lte: value } },查詢鍵值不大于指定值的所有文檔。

$eq

用法:{ field: { $eq: value } },查詢鍵值等于指定值的所有文檔。

$ne

用法:{ field: { $ne: value } },查詢鍵值不等于指定值的所有文檔。

$in

用法:{ field: { $in: [value1,value2] } },查詢鍵值等于指定數(shù)組中任意值的文檔

示例:

db.inventory.find( { amount : {$in:[50,58]} },{"_id":0})

{ "name" :"t2", "amount" : 50, "tags" : ["banana", "orange" ] }

{ "name" :"t3", "amount" : 58, "tags" : ["orange", "apple" ] }

$nin

用法:{ field: { $nin: [ value1, value2]} },查詢鍵不存在或者鍵值不等于指定數(shù)組的任意值的文檔

示例:

db.inventory.find({amount:{$nin:[50,58]}},{"_id":0})

{ "name" :"t1", "amount" : 16, "tags" : ["apple", "banana" ] }

邏輯操作符

$and

用法:{ $and: [ { }, { } ] },$and指定一個至少包含兩個表達式的數(shù)組,選擇出滿足該數(shù)組中所有表達式的文檔。and操作符使用短路操作,若第一個表達式的值為“false”,余下的表達式將不會執(zhí)行。

示例:

db.inventory.find({$and:[{"amount":{$gt:50}},{"amount":{$lt:70}}]},{"_id":0})

{ "name" :"t3", "amount" : 58, "tags" : ["orange", "apple" ] }

$or

用法:{ $or: [ { }, { }] },$or執(zhí)行邏輯OR運算,指定一個至少包含兩個表達式的數(shù)組,選擇出至少滿足數(shù)組中一條表達式的文檔。

示例:

db.inventory.find({$or:[{"amount":{$gt:50}},{"amount":{$lt:50}}]},{"_id":0})

{ "name" :"t1", "amount" : 16, "tags" : ["apple", "banana" ] }

{ "name" :"t3", "amount" : 58, "tags" : ["orange", "apple" ] }

$nor

用法:{ $nor: [ { }, { }] },$nor執(zhí)行邏輯NOR運算,指定一個至少包含兩個表達式的數(shù)組,選擇出都不滿足該數(shù)組中所有表達式的文檔。

示例:

db.inventory.find({$nor:[{"amount":{$gt:50}},{"amount":{$lt:50}}]},{"_id":0})

{ "name" :"t2", "amount" : 50, "tags" : ["banana", "orange" ] }

$not

用法:{ field: { $not: { } } },$not執(zhí)行邏輯NOT運算,選擇出不能匹配表達式的文檔,包括沒有指定鍵的文檔。$not操作符不能獨立使用,必須跟其他操作一起使用(除$regex)。

示例:

db.inventory.find({"amount":{$not:{$gt:50}}},{"_id":0})

{ "name" :"t1", "amount" : 16, "tags" : ["apple", "banana" ] }

{ "name" :"t2", "amount" : 50, "tags" : ["banana", "orange" ] }

元素操作符

$exists

用法:{ field: { $exists: } },斷言字段是否存在,如果$exists的值為true,選擇存在該字段的文檔;若值為false則選擇不包含該字段的文檔。

示例:

db.inventory.find({qty:{$exists:false}},{"_id":0})

{ "name" :"t1", "amount" : 16, "tags" : ["apple", "banana" ] }

{ "name" :"t2", "amount" : 50, "tags" : ["banana", "orange" ] }

{ "name" :"t3", "amount" : 58, "tags" : ["orange", "apple" ] }

db.inventory.find({amount:{$exists:true,$nin:[16,58]}},{"_id":0})

{ "name" :"t2", "amount" : 50, "tags" : ["banana", "orange" ] }

$mod

用法:{ field: { $mod: [ divisor, remainder ]} },匹配字段值對(divisor)取模,值等于(remainder)的文檔。

示例:

db.inventory.find({amount:{$mod:[5,0]}},{"_id":0})

{ "name" :"t2", "amount" : 50, "tags" : ["banana", "orange" ] }

$type

用法:{ field: { $type: } },選擇字段值為指定的BSON數(shù)據(jù)類型的文檔.

type>使用下面類型對應(yīng)的編號:

類型 ? ?類型 ? ?編號

Double ? ?雙精度 ? ?1

String ? ?字符串 ? ?2

Object ? ?對象 ? ?3

Array ? ?數(shù)組 ? ?4

Binary data ? ?二進制對象 ? ?5

Object id ? ?對象id ? ?7

Boolean ? ?布爾值 ? ?8

Date ? ?日期 ? ?9

Null ? ?未定義 ? ?10

Regular? Expression ? ?正則表達式 ? ?11

JavaScript ? ?JavaScript代碼 ? ?13

Symbol ? ?符號 ? ?14

JavaScript (with? scope) ? ?JavaScript代碼(帶范圍) ? ?15

32-bit integer ? ?32位整數(shù) ? ?16

Timestamp ? ?時間戳 ? ? 17

64-bit integer ? ? 64位整數(shù) ? ?18

Min key ? ?最小鍵 ? ?255

Max key ? ?最大鍵 ? ?127

如果文檔的鍵值是一個數(shù)組。那么$type將對數(shù)組里面的元素進行類型匹配而不是鍵值數(shù)組本身。

示例:

db.inventory.find({"amount":{$type:1}},{"_id":0})

{ "name" :"t1", "amount" : 16, "tags" : ["apple", "banana" ] }

{ "name" :"t2", "amount" : 50, "tags" : ["banana", "orange" ] }

{ "name" :"t3", "amount" : 58, "tags" : ["orange", "apple" ] }

MinKey和Maxkey表示可能的最小值和最大值,查詢示例:

db.post.insert({x:MinKey})

db.post.find({"x":{$type:-1}})

{ "_id" :ObjectId("55a14d2eb26f97b960389a61"), "x" : {"$minKey" : 1 } }

JavaScript查詢操作符

$regex

regex操作符查詢中可以對字符串的執(zhí)行正則匹配。MongoDB使用Perl兼容的正則表達式(PCRE)庫來匹配正則表達式,可以使用正則表達式對象或者regex操作符。

options(regex提供四個選項標(biāo)志)

i如果設(shè)置了這個修飾符,忽略大小寫。

m如果設(shè)置了這個修飾符,忽略換行。

s如果設(shè)置了這個修飾符,模式中的點號元字符匹配所有字符,包含換行符。如果沒有這個修飾符,點號不匹配換行符。

x如果設(shè)置了這個修飾符,模式中的沒有經(jīng)過轉(zhuǎn)義的或不在字符類中的空白數(shù)據(jù)字符總會被忽略,并且位于一個未轉(zhuǎn)義的字符類外部的#字符和下一個換行符之間的字符也被忽略。這個修飾符使被編譯模式中可以包含注釋。注意:這僅用于數(shù)據(jù)字符??瞻鬃址€是不能在模式的特殊字符序列中出現(xiàn),比如序列。

注:JavaScript只提供了i和m選項,x和s選項必須使用$regex操作符。

示例:查詢name鍵值以“3”結(jié)尾的文檔

db.inventory.find({name:/3/i},{"_id":0});

{ "name" :"t3", "amount" : 58, "tags" : ["orange", "apple" ] }

db.inventory.find( { name: { $regex: '.3',$options: 'i' } },{"_id":0} )

{ "name" :"t3", "amount" : 58, "tags" : ["orange", "apple" ] }

$where

$where操作符功能強大而且靈活,他可以使用任意的JavaScript作為查詢的一部分,包含JavaScript表達式的字符串或者JavaScript函數(shù)。不是非常必要時,一定要避免使用"where"査詢,因為它們在速度上要比常規(guī)査詢慢很多,每個文檔都要從BSON轉(zhuǎn)換成JavaScript對象,然后通過"where"的表達式來運行,同時還不能利用索引。所以,只在走投無路時才考慮"$where"這種用法。

示例:比較文檔中的兩個鍵的值是否相等。

db.fruit.insert({"apple":1,"banana": 4, "peach" : 4})

db.fruit.insert({"apple":3,"banana": 3, "peach" : 4})

查找出banana等于peach鍵值的文檔(4種方法):

db.fruit.find( { $where: "this.banana== this.peach" } )

{ "_id" :ObjectId("55a14f35b26f97b960389a62"), "apple" : 1,"banana" : 4, "peach" : 4 }

db.fruit.find( { $where: "obj.banana== obj.peach" } )

{ "_id" :ObjectId("55a14f35b26f97b960389a62"), "apple" : 1,"banana" : 4, "peach" : 4 }

db.fruit.find( { $where: function() {return (this.banana == this.peach) } } )

{ "_id" :ObjectId("55a14f35b26f97b960389a62"), "apple" : 1,"banana" : 4, "peach" : 4 }

db.fruit.find( { $where: function() {return obj.banana == obj.peach; } } )

{ "_id" :ObjectId("55a14f35b26f97b960389a62"), "apple" : 1,"banana" : 4, "peach" : 4 }

查出文檔中存在的兩個鍵的值相同的文檔

db.fruit.find({$where:function () {

? ? for (var current in this) {

? ? ? ? for (var other in this) {

? ? ? ? ? ? if (current != other &&this[current] == this[other]) {

? ? ? ? ? ? ? ? return true;

? ? ? ? ? ? }

? ? ? ? }

? ? }

? ? return false;

?}});

{ "_id" :ObjectId("55a14f35b26f97b960389a62"), "apple" : 1,"banana" : 4, "peach" : 4 }

{ "_id" :ObjectId("55a14f35b26f97b960389a63"), "apple" : 3,"banana" : 3, "peach" : 4 }

三 語法總結(jié)

1、find操作的永遠是文檔,所以find()中一定要有{}包裹限定條件

2、限定條件文檔編寫時,如果是key,后面都是跟文檔,如果是操作符,后面跟數(shù)組或字符串

3、$and$or$nor$not邏輯或、與、非操作符都是后面跟數(shù)組,并在數(shù)組中將多個限定文檔作為數(shù)組的元素。

4、$gt $lt $gte $lte$eq $ne算術(shù)操作符后面都是跟數(shù)字

5、$all查詢的是條件數(shù)組問文檔數(shù)組的子集,$in查詢的是鍵的值在條件數(shù)組中

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容