MongoDB學習筆記六—查詢下

来源:http://www.cnblogs.com/ginb/archive/2016/12/25/6219571.html
-Advertisement-
Play Games

查詢內嵌文檔 數據準備 方式1:查詢整個內嵌文檔 與普通查詢完全相同。但是,如果要查詢一個完整的子文檔,那麼子文檔必須精確匹配(順序以及個數都要一樣)。 > db.blog.find({"comments":{"author":"lf","votes":20}}) > 方式2:只針對其鍵/值對進行查 ...


查詢內嵌文檔

數據準備

> db.blog.find().pretty()
{
        "_id" : ObjectId("585694e4c5b0525a48a441b5"),
        "content" : "...",
        "comments" : [
                {
                        "comment" : "good post",
                        "author" : "jim",
                        "votes" : 15
                },
                {
                        "comment" : "i thought it was too short",
                        "author" : "yyb",
                        "votes" : 3
                },
                {
                        "comment" : "free watches",
                        "author" : "alice",
                        "votes" : 3
                }
        ]
}
{
        "_id" : ObjectId("585f659898992d5a44085fc0"),
        "content" : "query",
        "comments" : [
                {
                        "comment" : "good post two",
                        "author" : "yyb",
                        "votes" : 10
                },
                {
                        "comment" : "i thought it was vary good",
                        "author" : "mmq",
                        "votes" : 30
                },
                {
                        "comment" : "free watches two",
                        "author" : "lf",
                        "votes" : 20
                }
        ]
}
> 

方式1:查詢整個內嵌文檔

與普通查詢完全相同。但是,如果要查詢一個完整的子文檔,那麼子文檔必須精確匹配(順序以及個數都要一樣)。

 > db.blog.find({"comments":{"author":"lf","votes":20}})
 >

> db.blog.find({"comments":{"comment":"free watches two","author":"lf","votes":20}}).pretty()
{
        "_id" : ObjectId("585f659898992d5a44085fc0"),
        "content" : "query",
        "comments" : [
                {
                        "comment" : "good post two",
                        "author" : "yyb",
                        "votes" : 10
                },
                {
                        "comment" : "i thought it was vary good",
                        "author" : "mmq",
                        "votes" : 30
                },
                {
                        "comment" : "free watches two",
                        "author" : "lf",
                        "votes" : 20
                }
        ]
}
> 

方式2:只針對其鍵/值對進行查詢

> db.blog.find({"comments.author":"yyb","comments.votes":10}).pretty()
{
        "_id" : ObjectId("585f659898992d5a44085fc0"),
        "content" : "query",
        "comments" : [
                {
                        "comment" : "good post two",
                        "author" : "yyb",
                        "votes" : 10
                },
                {
                        "comment" : "i thought it was vary good",
                        "author" : "mmq",
                        "votes" : 30
                },
                {
                        "comment" : "free watches two",
                        "author" : "lf",
                        "votes" : 20
                }
        ]
}

如果想要查找由yyb發表的11分以上的投票。不能直接使用以下方式

> db.blog.find({"comments":{"author":"yyb","votes":{"$gt":11}}})
> 

 或者

> db.blog.find({"comments.author":"yyb","comments.votes":{"$gt":11}})//本來沒有,但卻查出來兩條
{ "_id" : ObjectId("585694e4c5b0525a48a441b5"), "content" : "...", "comments" : [ { "comment" : "good post", "author" : "jim", "votes" : 15 }, { "comment" : "i thought it was too short", "author" : "yyb", "votes" : 3 }, { "comment" : "free watches", "author" : "alice", "votes" : 3 } ] }
{ "_id" : ObjectId("585f659898992d5a44085fc0"), "content" : "query", "comments" : [ { "comment" : "good post two", "author" : "yyb", "votes" : 10 }, { "comment" : "i thought it was vary good", "author" : "mmq", "votes" : 30 }, { "comment" : "free watches two", "author" : "lf", "votes" : 20 } ] }

$elemMatch

要正確地指定一組條件,而不必指定每個鍵,就需要使用 $elemMatch 。這種模糊的命名條件句能用來在查詢條件中部分指定匹配數組中的單個內嵌文檔。

$elemMatch將限定條件進行分組,僅當需要對一個內嵌文檔的多個鍵操作時才會用到。

> db.blog.find({"comments":{"$elemMatch":{"author":"yyb","votes":{"$gt":11}}}})//無匹配結果
> db.blog.find({"comments":{"$elemMatch":{"author":"yyb","votes":{"$gte":10}}}}).pretty() { "_id" : ObjectId("585f659898992d5a44085fc0"), "content" : "query", "comments" : [ { "comment" : "good post two", "author" : "yyb", "votes" : 10 }, { "comment" : "i thought it was vary good", "author" : "mmq", "votes" : 30 }, { "comment" : "free watches two", "author" : "lf", "votes" : 20 } ] } >

 $where

用它可以在查詢中執行任意的js。這樣就能在查詢中做任何事情,為安全起見,應該嚴格限制或消除$where語句的使用。應該禁止終端用戶使用任意的$where語句。

如果函數返回true,文檔就作為結果集的一部分返回;如果為false,就不返回。

使用$where在速度上要比常規查詢慢很多。每個文檔都要從BSON轉換成js對象,然後通過$where表達式來運行。而且不能使用索引。實在不得已,最好先使用常規查詢(或索引)進行過濾,然後使用$where語句,這樣組合使用可以降低性能損失。

$where語句最常見的應用就是比較文檔中的兩個鍵的值是否相等。比如:

> db.foo.insert({"apple":1,"banana":6,"pach":3})
WriteResult({ "nInserted" : 1 })
> db.foo.insert({"apple":8,"banana":4,"pach":4})
WriteResult({ "nInserted" : 1 })
> db.foo.find({"$where":function(){
... for(var cur in this){
...   for(var other in this){
...      if(cur!=other && this[cur]==this[other]){
...        return true;
...       }
...     }
...   }
...   return false;
...   }});
{ "_id" : ObjectId("585f768398992d5a44085fc2"), "apple" : 8, "banana" : 4, "pach" : 4 }
> 

游標

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

> for(i=0;i<100;i++){
... db.coll.insert({x:i});
... }
WriteResult({ "nInserted" : 1 })
> var cursor=db.coll.find()
> while(cursor.hasNext()){
... obj=cursor.next();
... print(obj.x+"============"+obj._id);
... }

0============585f7c3a98992d5a44085fc3
1============585f7c3a98992d5a44085fc4
2============585f7c3a98992d5a44085fc5
3============585f7c3a98992d5a44085fc6

......

 

cursor.hasNext()檢查是否有後續結果存在,然後用cursor.next()獲取它。

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

> var coll=db.coll.find({"x":{"$lte":3}})
> coll.forEach(function(row){
... print(row._id+"========="+row.x);
... })
585f7d0298992d5a44086027=========0
585f7d0298992d5a44086028=========1
585f7d0298992d5a44086029=========2
585f7d0298992d5a4408602a=========3
> 

調用find時,shell並不立即查詢資料庫,而是等待真正開始獲得結果時才發送查詢,這樣在執行之前可以給查詢附加額外的選項。

幾乎游標對象的每個方法都返回游標本身,這樣就可以按照任意順序組成方法鏈。例如,下麵幾種表達是等價的:

> var cursor=db.coll.find().sort({"x":-1}).skip(10).limit(1)//實現分頁的方式:先倒序,跳過10條,取1條
> var cursor=db.coll.find().limit(1).sort({"x":-1}).skip(10)
> var cursor= db.coll.find().skip(10).limit(1).sort({"x":-1})

此時,查詢還沒有真正執行,所有這些函數都只是構造查詢。

> print(cursor)

DBQuery: test.coll -> { "query" : { }, "orderby" : { "x" : -1 } }

limit、sort、和skip

limit限制返回結果的數量,sort排序,skip忽略一定數量的結果。

> var cursor=db.coll.find().sort({"x":-1}).skip(10).limit(10)//實現分頁的方式:先倒序,跳過10條,取1條
> db.coll.find().limit(2)
{ "_id" : ObjectId("585f7d0298992d5a44086027"), "x" : 0 }
{ "_id" : ObjectId("585f7d0298992d5a44086028"), "x" : 1 }
......
> db.coll.find().skip(2)
{ "_id" : ObjectId("585f7d0298992d5a44086029"), "x" : 2 }
{ "_id" : ObjectId("585f7d0298992d5a4408602a"), "x" : 3 }
......
> db.coll.find().sort({"x":-1})
{ "_id" : ObjectId("585f7d0298992d5a4408608a"), "x" : 99 }
{ "_id" : ObjectId("585f7d0298992d5a44086089"), "x" : 98 }
......

避免使用skip略過大量結果,用skip略過少量的文檔還是不錯的。但是要是數量非常多的話,skip就會變得很慢,通常可以利用上次的結果來計算下一次查詢條件。

比如可以利用最後一個文檔中的date”的值最為查詢條件,來獲取下一頁:

> var page1=db.coll.find().sort({"date":-1}).limit(10)
> var lastest=null;
> while(page1.hasNext()){ latest=page1.next(); print(latest.x)}
> var page2=db.coll.find({"date":{"$gt":latest.date}}).sort({"date":-1}).limit(10)

比較順序

MongoDB處理不同類型的數據是有一定順序的。有時一個鍵的值可能是多種類型的。如果對這種混合類型的鍵排序,其順序是預先定義好的。優先順序從小到大,其順序如下。

(1)最小值

(2)Null

(3)數字

(4)字元串

(5)對象/文檔

(6)數組

(7)二進位數據

(8)對象id

(9)布爾型

(10)日期型

(11)時間戳

(12)正則表達式

(13)最大值

高級查詢選項

簡單查詢

> var cursor=db.coll.find({"x":1})

封裝查詢

有一些選項可以用於對查詢進行“封裝”。

比如:

var cursor= db.coll.find({x:{“$lt”:10}}).sort({"x":-1})

實際情況不是將 {x:{“$lt”:10} 作為查詢直接發送給資料庫,而是先將查詢封裝在一個更大的文檔中。

DBQuery: test.coll -> { "query" : { "x" : { "$lt" : 10 } }, "orderby" : { "x" : -1 } }

絕大多數驅動程式都提供了輔助函數,用於向查詢中添加各種選項。比如:

> db.coll.find({"x":{"$lt":2}})._addSpecial("$showDiskLoc",true);

{ "_id" : ObjectId("585f7d0298992d5a44086027"), "x" : 0, "date" : ISODate("2016-12-25T10:02:02.499Z"), "$recordId" : NumberLong(104) }

{ "_id" : ObjectId("585f7d0298992d5a44086028"), "x" : 1, "date" : ISODate("2016-12-25T10:02:02.499Z"), "$recordId" : NumberLong(105) }

> 

獲取一致結果

數據處理通常做法就是先把數據從MongoDB中取出來,然後做一些變換,最後在存回去。

結果比較少時,沒什麼問題。但是如果結果集比較大,MongoDB可能會多次返回同一個文檔。原因是:體積變大的文檔,可能無法保存回原先的位置。MongoDB會為更新後無法放回原位置的文檔重新分配存儲空間。

解決方案:對查詢進行快照。這樣查詢就在_id索引上遍歷執行,這樣可以保證每個文檔只被返回一次。

> db.coll.find().snapshot()

快照會使查詢變慢,如非必要,不建議使用。

游標生命周期

看待游標的兩種角度:客戶端游標以及客戶端游標表示的資料庫游標。前面所說的游標都是客戶端游標。

在伺服器端,游標消耗記憶體和其他資源。游標遍歷盡了結果之後,獲取客戶端發來消息要求終止,資料庫就會釋放這些資源。還有一些情況導致游標終止:

  1. 游標完成匹配結果的迭代時。
  2. 客戶端的游標已經不再作用域內,驅動程式會向服務端發送一條特別的消息,讓其銷毀游標。
  3. 一個游標在10分鐘之內沒有使用。

資料庫命令

shell中使用的輔助函數,都是對資料庫命令的封裝,而提供的更加簡單的介面。

> db.runCommand({"drop":"coll"})
{ "ns" : "test.coll", "nIndexesWas" : 1, "ok" : 1 }
> db.coll.drop()
false

查看所有的資料庫命令

> db.listCommands()

資料庫命令總會返回一個包含ok鍵的文檔,如果值是1,則表示成功,反之失敗,那麼命令的返迴文檔中就會有一個額外的鍵errmsg。用於描述失敗的原因。

>  db.runCommand({"drop":"coll"})
{ "ok" : 0, "errmsg" : "ns not found", "code" : 26 }

MongoDB中的命令被實現為一種特殊類型的查詢,這些特殊的查詢會在$cmd集合上執行。

runCommand只是接受一個命令文檔,並且執行與這個命令文檔等價的查詢。於是,drop命令會被轉換為如下代碼:

> db.$cmd.findOne({"drop":"coll"})
{ "ok" : 0, "errmsg" : "ns not found", "code" : 26 }

有些命令需要管理員許可權,而且要在admin資料庫上才能執行。如果當前位於其他的資料庫,但是需要執行一個管理員命令,可以使用 adminCommand

> db.runCommand({"shutdown":1})
{
        "ok" : 0,
        "errmsg" : "shutdown may only be run against the admin database.",
        "code" : 13
}
> db.adminCommand({"shutdown":1})
2016-12-25T21:32:31.474+0800 E QUERY    [thread1] Error: error doing query: failed: network error while attempting to run command 'shutdown' on host '127.0.0.1:27017'  :
DB.prototype.runCommand@src/mongo/shell/db.js:135:1
DB.prototype.adminCommand@src/mongo/shell/db.js:153:16
@(shell):1:1

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

-Advertisement-
Play Games
更多相關文章
  • listview經常結合下來刷新和上拉載入更多使用,本文總結了三種常用到的方案分別作出說明。 ...
  • 概述 本篇文章會從源碼(基於Android 6.0)角度分析Android中View的繪製流程,側重於對整體流程的分析,對一些難以理解的點加以重點闡述,目的是把View繪製的整個流程把握好,而對於特定實現細節則可以日後再對相應源碼進行研讀。在進行實際的分析之前,我們先來看下麵這張圖: 我們來對上圖做 ...
  • 鎖終端 輸入: <1>cd /Applications/Xcode.app 回車 結果顯示: Xcode.app 輸入: <2>sudo chown -hR root:wheel Contents 回車 結果顯示: WARNING: Improper use of the sudo command ...
  • 經過努力終於發現了最新的 解決cocoaPods安裝的辦法: taobao Gems 源已停止維護,現由 ruby-china 提供鏡像服務 第一步:安裝rvm, 不管需不需要升級ruby,rvm可以讓你擁有多個版本的Ruby,並且可以在多個版本之間自由切換。如果已經安裝過跳到第2步(rvm -v ...
  • 在之前的博文《Android中使用ViewPager實現屏幕頁面切換和引導頁效果實現》和《Android中Fragment的兩種創建方式》以及《Android中Fragment與Activity之間的交互(兩種實現方式)》中我們介紹了ViewPager以及Fragment各自的使用場景以及不同的實現 ...
  • 一、概述 運行時變更就是設備在運行時發生變化(例如屏幕旋轉、鍵盤可用性及語言)。發生這些變化,Android會重啟Activity,這時就需要保存activity的狀態及與activity相關的任務,以便恢復activity的狀態。 為此,google提供了三種解決方案: 下麵會逐一介紹三種情況,其 ...
  • 查詢這塊是重中之重, 關係到系統反應時間. 項目做到後期, 都是要做性能測試和性能優化的, 優化的時候, 資料庫這塊是一個大頭. sql格式: select 列名/* from 表名 where 條件 group by 列 having 條件 order by 列 asc/desc; 這裡牽涉到一個 ...
  • 在平常備庫和資料庫遷移的時候,當遇到大的資料庫的時候在用exp的時候往往是需要好幾個小時,耗費大量時間。oracle10g以後可以用expdp來導出資料庫花費的時間要遠小於exp花費的時間,而且文件也要小很多。 1.使用expdp要先在資料庫中創建directory,並給相應的用戶read,writ ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...