簡介
查詢文件是在MongoDB中執行許多不同操作所必需的一項基本技能。您需要能夠有效地查詢以檢索所需的文件,更新資料庫中的現有資訊,並瞭解文件之間的共性和差異。
在本指南中,我們將介紹如何為 MongoDB 編寫查詢的基礎知識,以幫助您根據要求檢索文件。我們將向您展示查詢如何在通用層面上工作,然後我們將探討 MongoDB 提供的各種運算子,以幫助您透過評估條件來縮小結果範圍。
如果您正在使用 MongoDB,請檢視 Prisma 的 MongoDB 聯結器!您可以使用 Prisma Client 自信地管理生產 MongoDB 資料庫。
要開始使用 MongoDB 和 Prisma,請檢視我們的從頭開始指南,或者如何新增到現有專案。
建立示例集合
在本文中,我們將使用一個名為 students 的集合和一個名為 teachers 的集合,它們都儲存在一個名為 school 的資料庫中。
您可以使用以下命令建立示例資料庫並填充集合:
use schooldb.students.insertMany([{first_name: "Ashley",last_name: "Jenkins",dob: new Date("January 08, 2003"),grade_level: 8},{first_name: "Brian",last_name: "McMantis",dob: new Date("September 18, 2010"),grade_level: 2},{first_name: "Leah",last_name: "Drake",dob: new Date("October 03, 2009")},{first_name: "Naomi",last_name: "Pyani"},{first_name: "Jasmine",last_name: "Took",dob: new Date("April 11, 2011")},{first_name: "Michael",last_name: "Rodgers",dob: new Date("February 25, 2008"),grade_level: 6},{first_name: "Toni",last_name: "Fowler"}])db.teachers.insertMany([{first_name: "Nancy",last_name: "Smith",subjects: ["vocabulary","pronunciation"]},{first_name: "Ronald",last_name: "Taft",subjects: ["literature","grammar","composition"]},{first_name: "Casey",last_name: "Meyers",subjects: ["literature","composition","grammar"]},{first_name: "Rebecca",last_name: "Carrie",subjects: ["grammar","literature"]},{first_name: "Sophie",last_name: "Daggs",subjects: ["literature","composition","grammar","vocabulary","pronunciation"]}])
基本查詢語法
現在您有兩個包含文件的集合,您可以嘗試如何檢索單個文件或文件組。從 MongoDB 獲取文件的主要方法是在相關集合上呼叫 find() 方法。
例如,要從 students 集合中收集所有文件,您可以不帶任何引數地呼叫 find():
db.students.find()
{ "_id" : ObjectId("60e8743b4655cbf49ff7cb83"), "first_name" : "Ashley", "last_name" : "Jenkins", "dob" : ISODate("2003-01-08T00:00:00Z"), "grade_level" : 8 }{ "_id" : ObjectId("60e875d54655cbf49ff7cb84"), "first_name" : "Brian", "last_name" : "McMantis", "dob" : ISODate("2010-09-18T00:00:00Z"), "grade_level" : 2 }{ "_id" : ObjectId("60e875d54655cbf49ff7cb85"), "first_name" : "Leah", "last_name" : "Drake", "dob" : ISODate("2009-10-03T00:00:00Z") }{ "_id" : ObjectId("60e877914655cbf49ff7cb86"), "first_name" : "Naomi", "last_name" : "Pyani" }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb87"), "first_name" : "Jasmine", "last_name" : "Took", "dob" : ISODate("2011-04-11T00:00:00Z") }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb88"), "first_name" : "Michael", "last_name" : "Rodgers", "dob" : ISODate("2008-02-25T00:00:00Z"), "grade_level" : 6 }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb89"), "first_name" : "Toni", "last_name" : "Fowler" }
為了使輸出更具可讀性,您還可以在 find() 之後鏈式呼叫 pretty() 方法:
db.<collection>.find().pretty()
{"_id" : ObjectId("60e8743b4655cbf49ff7cb83"),"first_name" : "Ashley","last_name" : "Jenkins","dob" : ISODate("2003-01-08T00:00:00Z"),"grade_level" : 8}{"_id" : ObjectId("60e875d54655cbf49ff7cb84"),"first_name" : "Brian","last_name" : "McMantis","dob" : ISODate("2010-09-18T00:00:00Z"),"grade_level" : 2}{"_id" : ObjectId("60e875d54655cbf49ff7cb85"),"first_name" : "Leah","last_name" : "Drake","dob" : ISODate("2009-10-03T00:00:00Z")}{"_id" : ObjectId("60e877914655cbf49ff7cb86"),"first_name" : "Naomi","last_name" : "Pyani"}{"_id" : ObjectId("60e8792d4655cbf49ff7cb87"),"first_name" : "Jasmine","last_name" : "Took","dob" : ISODate("2011-04-11T00:00:00Z")}{"_id" : ObjectId("60e8792d4655cbf49ff7cb88"),"first_name" : "Michael","last_name" : "Rodgers","dob" : ISODate("2008-02-25T00:00:00Z"),"grade_level" : 6}{"_id" : ObjectId("60e8792d4655cbf49ff7cb89"),"first_name" : "Toni","last_name" : "Fowler"}
您可以看到每個文件都添加了一個 _id 欄位。MongoDB 要求集合中的每個文件都有一個唯一的 _id。如果您在物件建立時未提供,它將為您新增一個。您可以使用此 ID 可靠地檢索單個物件:
db.student.find({_id : ObjectId("60e8792d4655cbf49ff7cb89")})
{ "_id" : ObjectId("60e8792d4655cbf49ff7cb89"), "first_name" : "Toni", "last_name" : "Fowler" }
按相等性過濾結果
您可以透過提供一個指定要查詢的欄位和值對的物件來按相等性過濾結果。
例如,您可以使用以下查詢獲取名為 "Brian" 的學生列表:
db.students.find({first_name: "Brian"})
{ "_id" : ObjectId("60e875d54655cbf49ff7cb84"), "first_name" : "Brian", "last_name" : "McMantis", "dob" : ISODate("2010-09-18T00:00:00Z"), "grade_level" : 2 }
您使用欄位-值表示法指定的任何屬性都將被解釋為相等查詢。如果您提供多個欄位,則文件必須所有值都相等才能匹配。
例如,如果執行與之前相同的相等匹配,但將 grade_level 包含為 3,則不會返回任何文件:
db.students.find({first_name: "Brian", grade_level: 3})
使用比較運算子進行過濾
雖然簡單的相等過濾很有用,但它的表達能力相當有限。對於其他型別的比較,MongoDB 提供了各種比較運算子,以便您可以透過其他方式進行查詢。
如果您使用其他程式語言,可用比較運算子的基本功能可能相當熟悉。大多數運算子透過將一個物件傳遞給欄位名來工作,該物件包含運算子和您想要比較的值,如下所示:
<field_name>: { <operator>: <value_to_compare_against> }
等於
$eq 運算子檢查提供的值與文件中的欄位值是否相等。在大多數情況下,這與我們上面使用的相等比較具有相同的功能。
例如,我們可以透過輸入以下內容來表達對名為 "Brian" 的學生的相同查詢:
db.students.find({first_name: { $eq: "Brian" }})
{ "_id" : ObjectId("60e875d54655cbf49ff7cb84"), "first_name" : "Brian", "last_name" : "McMantis", "dob" : ISODate("2010-09-18T00:00:00Z"), "grade_level" : 2 }
不等於
您還可以查詢不等於提供值的文件。此運算子是 $ne。
例如,查詢所有設定了 grade_level 的學生的一種方法是搜尋欄位未設定為 null 的條目:
db.students.find({grade_level: { $ne: null }})
{ "_id" : ObjectId("60e8743b4655cbf49ff7cb83"), "first_name" : "Ashley", "last_name" : "Jenkins", "dob" : ISODate("2003-01-08T00:00:00Z"), "grade_level" : 8 }{ "_id" : ObjectId("60e875d54655cbf49ff7cb84"), "first_name" : "Brian", "last_name" : "McMantis", "dob" : ISODate("2010-09-18T00:00:00Z"), "grade_level" : 2 }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb88"), "first_name" : "Michael", "last_name" : "Rodgers", "dob" : ISODate("2008-02-25T00:00:00Z"), "grade_level" : 6 }
大於
$gt 運算子允許您查詢欄位值大於所提供參考數字的文件。
例如,要查詢六年級以上學生的記錄,我們可以輸入:
db.students.find({grade_level: { $gt: 6 }})
{ "_id" : ObjectId("60e8743b4655cbf49ff7cb83"), "first_name" : "Ashley", "last_name" : "Jenkins", "dob" : ISODate("2003-01-08T00:00:00Z"), "grade_level" : 8 }
大於或等於
$gte 運算子表示查詢值等於或大於提供的值。
我們可以像上面那樣執行相同的查詢,但另外包括六年級的學生,方法是輸入:
db.students.find({grade_level: { $gte: 6 }})
{ "_id" : ObjectId("60e8743b4655cbf49ff7cb83"), "first_name" : "Ashley", "last_name" : "Jenkins", "dob" : ISODate("2003-01-08T00:00:00Z"), "grade_level" : 8 }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb88"), "first_name" : "Michael", "last_name" : "Rodgers", "dob" : ISODate("2008-02-25T00:00:00Z"), "grade_level" : 6 }
小於
使用 $lt 運算子查詢小於提供值的值。
例如,我們可以透過輸入以下內容來檢視 2010 年 1 月 1 日之前的出生日期:
db.students.find({dob: { $lt: new Date("January 1, 2010") }})
{ "_id" : ObjectId("60e8743b4655cbf49ff7cb83"), "first_name" : "Ashley", "last_name" : "Jenkins", "dob" : ISODate("2003-01-08T00:00:00Z"), "grade_level" : 8 }{ "_id" : ObjectId("60e875d54655cbf49ff7cb85"), "first_name" : "Leah", "last_name" : "Drake", "dob" : ISODate("2009-10-03T00:00:00Z") }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb88"), "first_name" : "Michael", "last_name" : "Rodgers", "dob" : ISODate("2008-02-25T00:00:00Z"), "grade_level" : 6 }
小於或等於
$lte 運算子檢查小於或等於所提供參考值的值。
例如,要查詢六年級及以下的學生,請輸入:
db.students.find({grade_level: { $lte: 6 }})
{ "_id" : ObjectId("60e875d54655cbf49ff7cb84"), "first_name" : "Brian", "last_name" : "McMantis", "dob" : ISODate("2010-09-18T00:00:00Z"), "grade_level" : 2 }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb88"), "first_name" : "Michael", "last_name" : "Rodgers", "dob" : ISODate("2008-02-25T00:00:00Z"), "grade_level" : 6 }
匹配一組值中的任意一個
$in 運算子的作用類似於 $eq 相等運算子,但它允許您在陣列中提供多個可能的值。例如,它不再檢查欄位值是否等於 8,而是可以檢查該值是否為 [8, 9, 10, 11] 中的任何一個。
$in 運算子也適用於正則表示式。例如,我們可以透過輸入以下內容來查詢所有名字以 'i' 或 'e' 結尾的學生:
db.students.find({first_name: {$in: [/i$/,/e$/]}})
{ "_id" : ObjectId("60e877914655cbf49ff7cb86"), "first_name" : "Naomi", "last_name" : "Pyani" }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb87"), "first_name" : "Jasmine", "last_name" : "Took", "dob" : ISODate("2011-04-11T00:00:00Z") }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb89"), "first_name" : "Toni", "last_name" : "Fowler" }
不匹配組中的任何值
上述過程的反面是查詢所有值不在給定陣列中的文件。其運算子是 $nin。
例如,我們可以透過輸入以下內容來查詢所有名字不以 'i' 或 'e' 結尾的學生:
db.students.find({first_name: {$nin: [/i$/,/e$/]}})
{ "_id" : ObjectId("60e8743b4655cbf49ff7cb83"), "first_name" : "Ashley", "last_name" : "Jenkins", "dob" : ISODate("2003-01-08T00:00:00Z"), "grade_level" : 8 }{ "_id" : ObjectId("60e875d54655cbf49ff7cb84"), "first_name" : "Brian", "last_name" : "McMantis", "dob" : ISODate("2010-09-18T00:00:00Z"), "grade_level" : 2 }{ "_id" : ObjectId("60e875d54655cbf49ff7cb85"), "first_name" : "Leah", "last_name" : "Drake", "dob" : ISODate("2009-10-03T00:00:00Z") }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb88"), "first_name" : "Michael", "last_name" : "Rodgers", "dob" : ISODate("2008-02-25T00:00:00Z"), "grade_level" : 6 }
使用邏輯運算子進行過濾
要形成更復雜的查詢,您可以使用邏輯運算子組合多個條件。邏輯運算子透過向其傳遞一個表示式物件或包含多個表示式物件的陣列來工作。
邏輯 AND 運算子
$and 運算子將返回滿足其傳入所有表示式的結果。$and 表示式中的每個表示式都必須評估為 true 才能返回。
例如,您可以使用 $and 查詢同時設定了出生日期和年級的學生:
db.students.find({$and: [{ dob: { $ne: null } },{ grade_level: { $ne: null } }]})
{ "_id" : ObjectId("60e8743b4655cbf49ff7cb83"), "first_name" : "Ashley", "last_name" : "Jenkins", "dob" : ISODate("2003-01-08T00:00:00Z"), "grade_level" : 8 }{ "_id" : ObjectId("60e875d54655cbf49ff7cb84"), "first_name" : "Brian", "last_name" : "McMantis", "dob" : ISODate("2010-09-18T00:00:00Z"), "grade_level" : 2 }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb88"), "first_name" : "Michael", "last_name" : "Rodgers", "dob" : ISODate("2008-02-25T00:00:00Z"), "grade_level" : 6 }
邏輯 OR 運算子
$or 運算子執行邏輯或計算。如果傳入的任何表示式為 true,則整個子句被認為是滿足的。
例如,您可以使用它來查詢缺少我們上面查詢的任一欄位的學生:
db.students.find({$or: [{ dob: { $eq: null } },{ grade_level: { $eq: null } }]})
{ "_id" : ObjectId("60e875d54655cbf49ff7cb85"), "first_name" : "Leah", "last_name" : "Drake", "dob" : ISODate("2009-10-03T00:00:00Z") }{ "_id" : ObjectId("60e877914655cbf49ff7cb86"), "first_name" : "Naomi", "last_name" : "Pyani" }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb87"), "first_name" : "Jasmine", "last_name" : "Took", "dob" : ISODate("2011-04-11T00:00:00Z") }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb89"), "first_name" : "Toni", "last_name" : "Fowler" }
邏輯 NOT 運算子
$not 運算子否定傳入表示式的值。它不作用於表示式陣列,因為 $not 是一個一元運算子,它直接作用於單個定義運算子表示式。它不作用於表示式陣列,因為它是一個一元運算子,它直接作用於定義運算子表示式的單個物件。
這導致語法與之前的運算子略有不同。它不是包裝一個完整的欄位和值表示式,而是將 $not 用作欄位匹配值的一部分,並且它只接受一個運算子表示式作為其引數,而不是一個完整的表示式(欄位名在 $not 表示式之外而不是之內)。
例如,我們可以透過輸入以下內容來查詢所有沒有 2010 年以前生日的學生。這與檢查 dob 條目是否小於 2010 年不同,因為它還會返回任何未設定該欄位的文件:
db.students.find({dob: {$not: {$lt: new Date("January 1, 2010")}}})
{ "_id" : ObjectId("60e875d54655cbf49ff7cb84"), "first_name" : "Brian", "last_name" : "McMantis", "dob" : ISODate("2010-09-18T00:00:00Z"), "grade_level" : 2 }{ "_id" : ObjectId("60e877914655cbf49ff7cb86"), "first_name" : "Naomi", "last_name" : "Pyani" }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb87"), "first_name" : "Jasmine", "last_name" : "Took", "dob" : ISODate("2011-04-11T00:00:00Z") }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb89"), "first_name" : "Toni", "last_name" : "Fowler" }
邏輯 NOR 運算子
$nor 運算子接受一個物件陣列,並返回不匹配這些物件中指定任何條件的文件。只有未能透過所有條件的文件才會被返回。
例如,如果您想檢索不在六年級且姓氏不以“s”結尾的學生文件,您可以輸入:
db.students.find({$nor: [{ grade_level: 6 },{ last_name: /s$/ }]})
{ "_id" : ObjectId("60e875d54655cbf49ff7cb85"), "first_name" : "Leah", "last_name" : "Drake", "dob" : ISODate("2009-10-03T00:00:00Z") }{ "_id" : ObjectId("60e877914655cbf49ff7cb86"), "first_name" : "Naomi", "last_name" : "Pyani" }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb87"), "first_name" : "Jasmine", "last_name" : "Took", "dob" : ISODate("2011-04-11T00:00:00Z") }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb89"), "first_name" : "Toni", "last_name" : "Fowler" }
基於存在性進行過濾
其他一些測試方法基於欄位或值的狀態。
例如,$exists 過濾器檢查文件中是否存在某個欄位。您可以將 $exists 設定為 true 或 false 來確定要檢索哪些文件。
例如,如果您想查詢具有年級資訊的學生文件,您可以輸入:
db.students.find({grade_level: { $exists: true }})
{ "_id" : ObjectId("60e8743b4655cbf49ff7cb83"), "first_name" : "Ashley", "last_name" : "Jenkins", "dob" : ISODate("2003-01-08T00:00:00Z"), "grade_level" : 8 }{ "_id" : ObjectId("60e875d54655cbf49ff7cb84"), "first_name" : "Brian", "last_name" : "McMantis", "dob" : ISODate("2010-09-18T00:00:00Z"), "grade_level" : 2 }{ "_id" : ObjectId("60e8792d4655cbf49ff7cb88"), "first_name" : "Michael", "last_name" : "Rodgers", "dob" : ISODate("2008-02-25T00:00:00Z"), "grade_level" : 6 }
基於陣列特性進行過濾
您還可以透過文件中包含的陣列進行查詢。有許多運算子可用於根據陣列元素或其他屬性進行匹配。
指定必需元素
$all 運算子返回包含所給定所有元素的陣列的文件。
例如,如果您只想檢索同時教授寫作和語法的教師,您可以輸入:
db.teachers.find({subjects: {$all: [ "composition", "grammar" ]}})
{ "_id" : ObjectId("60eddca65eb74f5c676f3bab"), "first_name" : "Ronald", "last_name" : "Taft", "subjects" : [ "literature", "grammar", "composition" ] }{ "_id" : ObjectId("60eddca65eb74f5c676f3bac"), "first_name" : "Casey", "last_name" : "Meyers", "subjects" : [ "literature", "composition", "grammar" ] }{ "_id" : ObjectId("60eddca65eb74f5c676f3bae"), "first_name" : "Sophie", "last_name" : "Daggs", "subjects" : [ "literature", "composition", "grammar", "vocabulary", "pronunciation" ] }
一個元素的多個要求
$elemMatch 運算子返回文件,如果被測試的陣列中至少包含一個滿足所有提供條件的元素。
舉一個相當無用的例子,要返回教授的科目在字母順序上介於“文學”和“詞彙”之間的教師文件,您可以輸入:
db.teachers.find({subjects: {$elemMatch: {$gt: "literature",$lt: "vocabulary"}}})
{ "_id" : ObjectId("60eddca65eb74f5c676f3baa"), "first_name" : "Nancy", "last_name" : "Smith", "subjects" : [ "vocabulary", "pronunciation" ] }{ "_id" : ObjectId("60eddca65eb74f5c676f3bae"), "first_name" : "Sophie", "last_name" : "Daggs", "subjects" : [ "literature", "composition", "grammar", "vocabulary", "pronunciation" ] }
教授“發音”的兩位老師都列在這裡,因為這是唯一滿足兩個條件的元素。
按陣列大小查詢
最後,您可以使用 $size 運算子查詢特定大小的文件。例如,要查詢所有教授三門課程的教師,請輸入:
db.teachers.find({subjects: { $size: 3 }})
{ "_id" : ObjectId("60eddca65eb74f5c676f3bab"), "first_name" : "Ronald", "last_name" : "Taft", "subjects" : [ "literature", "grammar", "composition" ] }{ "_id" : ObjectId("60eddca65eb74f5c676f3bac"), "first_name" : "Casey", "last_name" : "Meyers", "subjects" : [ "literature", "composition", "grammar" ] }
總結
在本指南中,我們介紹瞭如何使用 MongoDB 資料庫查詢文件。我們講解了 find() 方法的基本工作原理以及如何使其輸出更具可讀性。之後,我們查看了 MongoDB 提供的許多運算子,以指定您感興趣的文件的精確引數。
瞭解如何編寫查詢以縮小結果範圍並篩選出符合您規範的文件,對於讀取和更新資料都非常重要。透過熟悉運算子的各種鏈式使用方式,您可以表達匹配不同型別文件的複雜要求。
如果您正在使用 MongoDB,請檢視 Prisma 的 MongoDB 聯結器!您可以使用 Prisma Client 自信地管理生產 MongoDB 資料庫。
要開始使用 MongoDB 和 Prisma,請檢視我們的從頭開始指南,或者如何新增到現有專案。
常見問題
您可以在 find 語句中使用 $gt 運算子來查詢日期欄位大於特定日期的文件。
基本語法如下:
db.collection.find( { <Field Name>: { $gt:ISODate('Date here') } } )
MongoDB 資料庫查詢分析器是一個工具,它收集有關針對正在執行的 mongod 例項執行的資料庫命令的詳細資訊。
這包括 CRUD 操作以及配置和管理命令。這在嘗試對慢速操作進行排序時特別有用。
基本語法如下:
{ $strLenCP: "Hello World!" }
這個特定的字串將返回 12。
要僅查詢更大集合中欄位的唯一值,您可以使用 distinct() 方法。
基本語法如下:
db.collection.distinct("<Field_Name>")
這將返回集合中特定欄位的所有唯一值,沒有重複。
您可以使用 mongoexport 命令列工具將資料庫內容匯出為 JSON。需要注意的是,這不應在 mongo shell 中執行,而應在命令列中執行。
基本語法如下,我們指定集合匯出的輸出為 json:
mongoexport --collection=events --db=reporting --out=events.json
