MongoDB系列一(查詢).

来源:https://www.cnblogs.com/jmcui/archive/2018/03/17/8520489.html
-Advertisement-
Play Games

一、簡述 MongoDB中使用find來進行查詢。查詢就是返回一個集合中文檔的子集,子集合的範圍從0個文檔到整個集合。預設情況下,"_id"這個鍵總是被返回,即便是沒有指定要返回這個鍵。("_id"是一個集合中每個文檔的唯一標識) 查詢的使用上有限制,傳遞給資料庫的查詢文檔必須是常量。(當然,在你的 ...


一、簡述

    MongoDB中使用find來進行查詢。查詢就是返回一個集合中文檔的子集,子集合的範圍從0個文檔到整個集合。預設情況下,"_id"這個鍵總是被返回,即便是沒有指定要返回這個鍵。("_id"是一個集合中每個文檔的唯一標識)

    查詢的使用上有限制,傳遞給資料庫的查詢文檔必須是常量。(當然,在你的代碼里可以是正常的變數)

    一個鍵可以有任意多個條件,但是一個鍵不能對應多個更新修改器。

    條件語句是內層文檔的鍵,而修改器是外層文檔的鍵。

二、使用find或者findOne函數和查詢文檔數據庫執查詢

1、db.userInfo.find()
--查詢所有數據,相當於 select * from userInfo

2、db.userInfo.find({age:22})
--查詢 age = 22 的記錄,相當於 select * from userInfo where age = 22

3、db.userInfo.find({age:22,name:'zhangsan'})
--查詢 age = 22 並且name = 'zhangsan' 的記錄,相當於  select * from userInfo where age = 22 and name = 'zhangsan'

tips:匹配正則表達式(4、5):

4、db.userInfo.find({name:/mongo/})
--查詢 name 中包含 mongo 的數據, 相當於 select * from userInfo where name like '%mongo%'

5、db.userInfo.find({name:/^mongo/})
--查詢 name 中以mongo開頭的,相當於 select * from userInfo where name like 'mongo%'

6、db.userInfo.findOne()
--查詢第一條數據,相當於 select top 1 * from userInfo 與 db.userInfo.find().limit(1)

7、db.userInfo.distinct("name")
--查詢後去掉當前集合中的某列的重覆數據,相當於 select distinct name from userInfo

tips:find 查詢的第一個大括弧表示查詢條件,第二個大括弧表示要顯示的欄位(預設全顯示 ):

8、db.userInfo.find({},{name:1,age:1})
--查詢指定列name、age的數據,相當於 select name,age from userInfo

9、db.userInfo.find({},{name:0})
--不希望結果集中顯示 name 這個欄位

tips:排序分頁

10、db.userInfo.find().sort({age:1})
--按照年齡升序
11、db.userInfo.find().sort({age:-1})
--按照年齡降序

12、db.userInfo.find().limit(5)
--查詢前5條數據,相當於 select top 5 * from userInfo

13、db.userInfo.find().skip(10)
--查詢 10條以後的數據 select * from userInfo where id not in (select top 10 * from userInfo)

14、db.userInfo.find().limit(5).skip(0)
--可用於分頁 limit是pageSize,skip是 第幾頁*pageSize(從第0頁開始)

15、db.userInfo.find({sex:null}) 

-- 特定類型的查詢,比如 null 。它確實可以匹配自身,但是它不僅可以匹配這個鍵為 null 的文檔,也能匹配不包含這個鍵的文檔。如果僅想匹配這個鍵位 null 的文檔,需要修改如下:

-- db.userInfo.find({sex:{'$in':[null],'$exists':true}})

三、使用條件查詢實現圍查詢、數據集包含查詢、不等式查詢,以及其他一些查詢

1、$lt(小於)、$lte(小於等於)、$ge(大於)、$gte(大於等於)、$ne 不等於

db.userInfo.find({age:{$gt:22}})
    --查詢age > 22 的記錄,相當於 select * from userInfo where age > 22
db.userInfo.find({age:{$lt:22}})
    --查詢age < 22 的記錄,相當於 select * from userInfo where age < 22
db.userInfo.find({age:{$gte:22}})
   --查詢 age >= 22 的記錄,相當於 select * from userInfo where age >= 22
db.userInfo.find({age:{$lte:22}})
   --查詢 age <= 22 的記錄 ,相當於 select * from userInfo where age <= 22
db.userInfo.find({age:{$gte:23,$lte:26}})
   --查詢 age >= 23 並且 age <=26 的記錄 , 相當於 select * from userInfo where age >= 23 and age <=26

db.userInfo.find({age:{$ne:23}})
    --查詢 age != 23 的記錄 , 相當於 select * from userInfo where age != 23

tips:很遺憾,並沒有 $eq(等於)這個操作符。

2、元條件句 $and 、$or、$not

         元條件句:即可以用在任何其他條件之上 。

$and 總是希望儘可能用最少的條件來限定結果的範圍

db.userInfo.find({"$and" : [{x : {"$lt" : 1}}, {x : 4}]})
    --會匹配那些"x"欄位的值小於等於1並且等於4的文檔。雖然這兩個條件看起來是矛盾的,但是這是完全有可能的,比如,如果"x"欄位的值是這樣一個數組{"x" : [0,4]},那麼這個文檔就與查詢條件相匹配。
    --查詢優化器不會對"$and"進行優化,這與其他操作符不同。如果把上面的查詢改成下麵這樣,效率會更高:db.userInfo.find({x : {"$lt" : 1, "$in" : [4]}})

$or 第一個條件應該儘可能匹配更多的文檔,這樣才是最為高效的

db.userInfo.find({$or:[{age:22},{age:25}])
    --or與查詢,相當於select * from userInfo where age = 22 or age = 25

$not 用在其他條件上的取反,雖然是元條件句,但是不能放在外層文檔(否則:unknown top level operator: $not),並且後面必須跟正則表達式或者文檔(否則:$not needs a regex or a document)。

db.userInfo.find({age:{'not':{gt:23}}});
    -- 對於 age>23 返回的文檔取反集
db.product.find({name:{$not:/ang/}});
   -- 對 name 與正則匹配的結果取反集合

3、$in、$nin、$all、$size、slice 、elemMatch

$in 可以用來查詢一個鍵的多個值
 db.userInfo.find({age : {"$in" : [22, 23, 24]}})
    --查詢年齡等於22、23、24的文檔
$nin$in 相反,用來查詢一個鍵不屬於多個值的文檔。

$all (匹配數組)
db.food.find({fruit : {$all : ["apple", "banana"]}})
   -- 查詢 fruit 既含有 apple,又含有banana 的文檔。
   -- 當然,也可以不使用$all 匹配數組,比如 db.food.find({fruit : ["apple", "banana","orange"]}) 但是,這樣子只能唯一匹配數組為["apple", "banana","orange"] 的文檔,而且查詢數組條件還要保證相同的元素順序。
   --可以使用 key.index 查詢數組特定位置的元素。db.food.find({"fruit.2" : "peach"})

$size(匹配數組)
    --db.food.find({"fruit" : {"$size" : 3}})
    --匹配數組長度為3的文檔 

slice(匹配數組)
  --$slice 用在find的第二個參數,用來查找某個鍵匹配的數組元素的一個子集。
  --使用"$slice"時將返迴文檔中的所有鍵。
  --db.blog.findOne({},{comments:{"$slice":2}}) 返回 結果文檔中comments數組的前兩個子集
  --db.blog.findOne({},{comments:{"$slice":[23,10]}}) 返回 結果文檔中comments數組的 24-33 子集,不夠則全返回。
  --db.blog.findOne({},{comments:{"$slice":-1}}) 返回 結果文檔中comments數組的最後一個子集 

$elemMatch(匹配數組)
  --查詢匹配有兩種。數組匹配和非數組匹配。非數組匹配必須鍵的值滿足每一條查詢條件才行。數組匹配只要鍵的數組元素分別滿足查詢條件即可。比如:

            

     

                         -- $elemMatch 可以讓數組的元素分別要滿足查詢條件,但是 $elemMatch 不會匹配非數組元素!!

                         -- db.test.find({"x" : {"$elemMatch" : {"$gt" : 10, "$lt" : 20}}) 

4、其他 $exists 、$mod

$exists
   --查詢某個鍵時候存在
  -- db.userInfo.find({sex:{$exists:true}}) 返回鍵名含有sex的文檔
  -- db.userInfo.find({sex:{$exists:false}}) 返回鍵名不含有sex的文檔

$mod
  --$mod會將查詢的值除以第一個給定值,若餘數等於第二個給定值則匹配成功
  -- db.userInfo.find({id : {"$mod" : [5, 1]}}

四、查詢將會返回一個數據,游只會在你需要才將需要的文檔批量返回 

資料庫使用游標返回find的執行結果。客戶端對游標的實現通常能夠對最終結果進行有效的控制。可以限制結果的數量,略過部分結果,根據任意鍵按任意順序的組合對結果進行各種排序,或者是執行其他一些強大的操作。

var cursor = db.driverLocation.find();
while (cursor.hasNext()){
     var object = cursor.next();
     print(object.type);
    }

游標類還實現了JavaScript的迭代器介面,所以可以在forEach迴圈中使用:

var cursor = db.driverLocation.find();
cursor.forEach(function(x){
    print(x.type);
    });    

    調用find時,shell並不立即查詢資料庫,而是等待真正開始要求獲得結果時才發送查詢,這樣在執行之前可以給查詢附加額外的選項。幾乎游標對象的每個方法都返回游標本身,這樣就可以按任意順序組成方法鏈。例如,下麵幾種表達是等價的:
> var cursor = db.foo.find().sort({"x" : 1}).limit(1).skip(10);
> var cursor = db.foo.find().limit(1).sort({"x" : 1}).skip(10);
> var cursor = db.foo.find().skip(10).limit(1).sort({"x" : 1});

此時,查詢還沒有真正執行,所有這些函數都只是構造查詢。當執行 cursor.hasNext() 的時候,查詢才真正被執行。這時,查詢被髮往伺服器。shell立刻獲取前100個結果或者前4 MB數據(兩者之中較小者),這樣下次調用next或者hasNext時就不必再次連接伺服器取結果了。客戶端用光了第一組結果,shell會再一次聯繫資料庫,使用getMore請求提取更多的結果。getMore請求包含一個查詢標識符,向資料庫詢問是否還有更多的結果,如果有,則返回下一批結果。這個過程會一直持續到游標耗盡或者結果全部返回。

游標的生命周期:首先,游標完成匹配結果的迭代時,它會清除自身。另外,如果客戶端的游標已經不在作用域內了,驅動程式會向伺服器發送一條特別的消息,讓其銷毀游標。最後,即便用戶沒有迭代完所有結果,並且游標也還在作用域中,如果一個游標在10分鐘內沒有使用的話,資料庫游標也會自動銷毀。

五、還有很多針對游標執行的元操作,包括忽略一定數量的結果,或者限定返回結果的數量,以及對結果排序。 

   -- MongoDB處理不同類型的數據是有一定順序的。有時一個鍵的值可能是多種類型的,例如,整型和布爾型,或者字元串和null。如果對這種混合類型的鍵排序,其排序順序是預先定義好的。優先順序從小到大,其順序如下:

1. 最小值;
2. null;
3. 數字(整型、
4. 字元串;
5. 對象/文檔;
6. 數組;
7. 二進位數據
8. 對象ID;
9. 布爾型;
10. 日期型;
11. 時間戳;
12. 正則表達式
13. 最大值 。

    -- 不用 skip 進行分頁

    如前文提到的,一般分頁我們用 db.userInfo.find().limit(pageSize).skip(第n頁 * pageSize) 來實現。但是我們註意到,如果數據量大的話,我們總是先取出前 n*pageSize 的條數然後再捨棄掉,顯得很不合算。為此,《MongoDB權威指南》向我們介紹了一種方式:利用時間進行排序,拿到前一頁的最後時間,取出時間大於上一頁最後時間的 pageSize 條記錄,如下:

var latest = null;
//顯示第一頁
var page1 = db.foo.find().sort({"date" : -1}).limit(100)
while (page1.hasNext()) {
latest = page1.next();
display(latest);
}
// 獲取下一頁
var page2 = db.foo.find({"date" : {"$gt" : latest.date}});
page2.sort({"date" : -1}).limit(100);

 但是,我發現這樣寫還是會存在很多問題,比如說:

1、跟上一頁最後一個文檔的時間一樣的文檔如果有多個呢?那這樣不是會導致一些文檔被漏掉了嗎?

2、上一頁、下一頁或許可以解決。那麼如果用戶點擊第四頁、第五頁呢?

    -- 獲取一致結果

    數據處理通常的做法是先將數據從資料庫中取出來,做一些變換以後,再保存回資料庫。但是,MongoDB這邊有個機制就是,如果拿出來處理的數據處理後導致體積比原先大很多,會導致數據放不回原來的位置,而把這個數據挪至集合的末尾處。從而引發的隱患就是:分頁查詢到最後一頁的時候,又取到了原來的數據。

    應對這個問題的方法就是對查詢進行快照(snapshot)。如果使用了這個選項,查詢就在"_id"索引上遍歷執行,這樣可以保證每個文檔只被返回一次。

    db.foo.find().snapshot()
    快照會使查詢變慢,所以應該只在必要時使用快照。例如,mongodump預設在快照上使用查詢。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.將iso鏡像文件上傳到linux系統。註意要將文件放在合適的目錄下,因為後面機器重啟時還要自動掛載,所以此次掛載成功之後該文件也不要刪除。 2.將iso光碟掛載到/mnt/iso目錄下。 (1)先創建掛載的目標目錄/mnt/iso (2)接著使用mount -o loop /data/iso/r ...
  • 早上群上討論了一下systemd的作用,還導致了一個人的直接退群,出於求知心理,搜索了一些systemd,對此也作出了一些相應的整理; 一、systemd的誕生: 學習嵌入式bootloader與kernel銜接的時候,就入門了init進程;init進程也就是系統的第一個進程,PID號為1; ini ...
  • 在同一ip下添加多個功能變數名稱站點! 1.查看ip 命令:ifconfig 2.添加功能變數名稱 命令:vi /etc/hosts 輸入功能變數名稱:如 192.168.160.127 www.test.com 192.168.160.127 www.test2.com 3.創建要配置站點的文件夾及文件 .var/www ...
  • 本文目錄:1.簡介2.安裝heartbeat 2.1 編譯安裝Heartbeat3.heartbeat相關配置文件 3.1 配置文件ha.cf 3.2 配置文件authkeys 3.3 配置文件haresources4.示例:heartbeat為httpd提供高可用服務 1.簡介 heartbeat ...
  • 第一篇 基礎篇 第1章 Linux概述 1.1 Linux的起源 1991年芬蘭學生Linus Torvalds寫的磁碟驅動和文件系統開源發佈,Linux即“Linus的Minix”。 1994年內核1.0版發佈,最新內核版本4.14.11。 1.2 追溯到Unix 1969年AT&T貝爾實驗室的一 ...
  • Exp1 PC平臺逆向破解(5)M_20154304張懷珺 實踐目標 本次實踐的對象是一個名為pwn1的 linux 可執行文件。該程式正常執行流程是:main調用foo函數,foo函數會簡單回顯任何用戶輸入的字元串。該程式同時包含另一個代碼片段,getShell,會返回一個可用Shell。正常情況 ...
  • 一般資料庫系統中經常使用的字典的設計 字典(Dictionary) 欄位名 類型 說明 編號 Char(16) 間斷增量(Not Null,PK) 分類名稱 Varchar(64) 用來進行過濾選取字典表相關域 內容 Varchar(255) 上級編號 Char(16) Char(16) 取Dict ...
  • 今天徹底決定了,不再找工作,自己也覺得不適合找工作,實在找不到工作就辦暫緩就業。 說下今天畢設的準備吧,今天算是正式跟著視頻敲代碼了,寫了些SQL,把表建好了。 下麵是具體的SQL,但是過程怎麼寫的就不展開講了吧,主要講遇到的問題。 暫時是只有5張表,但是老師畢竟是個教前端的,連他自己都說這個表建的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...