返回
Featured image of post MongoDB - 深入Find

MongoDB - 深入Find

MongoDB - 想查?查給他五花八門

FindOptions 相關參數

  • limit:筆數
  • sort:排序
  • projection:返回指定欄位
  • skip:跳過 N 個欄位

基本使用

findOne - 單筆查詢

package 源碼

findOne<T = TSchema>(filter: Filter<TSchema>, options?: FindOptions): Promise<T | null>;
interface User {
    name: string
    age: number
    address: string
}
const collection: Collection<User> = db.collection<User>("user");
const query: Filter<User> = {
  name: 'Fred'
}
await collection.findOne(query);

find - 多筆查詢

package 源碼

find(filter: Filter<TSchema>, options?: FindOptions): FindCursor<WithId<TSchema>>;
interface User {
    name: string
    age: number
    address: string
}
const query: Filter<User> = {
  name: /F/
}
const cursor = collection.find(query);
let users = await cursor.toArray()    // 這才是回傳陣列欄位

返回指定欄位

interface User {
    name: string
    age: number
    address: string
}
const query: Filter<User> = {
  name: /F/
}
const option: FindOptions = {
  sort: { name: -1 }, // 排序
  projection: { name: true, address: true }, // 僅回傳需要的欄位,這就不會回傳 age
}
type ResultUser = Pick<Store, "name" | "address">;
const user = await collection.findOne<ResultUser>(query, option);

分頁搜尋

const req = {
  rows: 10,   // 筆數
  page: 1,    // 頁面
}

const query: Filter<User> = {
  name: /F/
}
const option: FindOptions = {
  sort: { name: -1 }, // 指定某欄位排序
  skip: req.rows * (req.page - 1),
  limit: req.rows
}
type ResultUser = Pick<Store, "name" | "address">;
const cursor = collection.find(query, option);
let users = await cursor.toArray()    // 這才是回傳陣列欄位

運算符

於Find中使用是針對 Filter<TSchema> 進行運算

比較查詢 (Comparison Query)

運算符翻譯格式
$eq=={field: {$eq: value} }
$gt>{field: {$gt: value} }
$gte>={field: {$gte: value} }
$in= 範圍 ex == 1~15 1>= && <=15{ field: { $in: [value1, value2, … valueN ] } }
$lt<{field: {$lt: value} }
$lte<={field: { $lte: value} }
$ne!={field: {$ne: value} }
$nin!= 範圍 ex != 1~15 1< && >15{field: {$nin: value} }
// Example
interface User {
    name: string
    age: number
    address: string
}
const query: Filter<User> = {
  name: {
    $eq : 'Fred'
  }
}

邏輯查詢 (Logical Query)

運算符翻譯格式
$and&&{ $and:[{expression1}, {expression2}, … ,{expressionN} ] }
$or||{ $or: [{expression1}, {expression2}, … {expressionN} ] }
// Example
interface User {
    name: string
    age: number
    address: string
}
const query: Filter<User> = {
  $or : [
    {
      name: 'Fred'
    },
    {
      name: 'Leo'
    },
  ]
}

元素查詢 (Element Query)

略,目前感覺用不到

評估查詢 (Evaluation Query) - 進階

運算符翻譯格式
$regex正則表示式匹配{ field: /pattern/options }
$mod餘數運算{ field: { $mod: [ divisor, remainder ] } }
$text文字索引的欄位內容執行文字搜尋{$text:{ $search:string, $language: string, $caseSensitive: boolean, $diacriticSensitive: boolean }}
$where匹配javascript表示式{ $where: function() { return …; } }
$expr使用聚合表示式{ $expr: { expression } }
$jsonSchema匹配json綱要{ $jsonSchema: schema }
  • $regex

    // Example
    interface User {
        name: string
        age: number
        address: string
    }
    const query: Filter<User> = {
        {
          name: { $regex: /F/ }
        },
    }
    
  • $mod

    db.inventory.insertMany( [
      { "_id" : 1, "item" : "abc123", "qty" : 0 },
      { "_id" : 2, "item" : "xyz123", "qty" : 5 },
      { "_id" : 3, "item" : "ijk123", "qty" : 12 }
    ] )
    db.inventory.find( { qty: { $mod: [ 4, 0 ] } } )
    // { "_id" : 1, "item" : "abc123", "qty" : 0 }
    // { "_id" : 3, "item" : "ijk123", "qty" : 12 }
    
  • $text

    運算符型別翻譯
    $searchstring查詢,這功能很好用
    $languagestring(ISO 639-1 ) 但很抱歉沒中文
    $caseSensitiveboolean大小寫敏感,base on 語系
    $diacriticSensitiveboolean相似音,base on 語系
    db.articles.insertMany( [
        { _id: 1, subject: "coffee", author: "xyz", views: 50 },
        { _id: 2, subject: "Coffee Shopping", author: "efg", views: 5 },
        { _id: 3, subject: "Baking a cake", author: "abc", views: 90  },
        { _id: 4, subject: "baking", author: "xyz", views: 100 },
        { _id: 5, subject: "Café Con Leche", author: "abc", views: 200 },
        { _id: 6, subject: "Сырники", author: "jkl", views: 80 },
        { _id: 7, subject: "coffee and cream", author: "efg", views: 10 },
        { _id: 8, subject: "Cafe con Leche", author: "xyz", views: 10 }
    ] )
    
    db.articles.find( { $text: { $search: "coffee" } } )
    
    // { _id: 1, subject: 'coffee', author: 'xyz', views: 50 },
    // { _id: 7, subject: 'coffee and cream', author: 'efg', views: 10 },
    // { _id: 2, subject: 'Coffee Shopping', author: 'efg', views: 5 }
    
  • $where
    需將MongoDB啟用 JavaScript Enablement功能(預設即啟用),這邊先將這功能略過,若要使用 Aggregation(聚合)功能需要進行 javascript查詢 建議使用$function 代替 $where

    db.players.insertMany([
      { _id: 12378, name: "Steve", username: "steveisawesome", first_login: "2017-01-01" },
      { _id: 2, name: "Anya", username: "anya", first_login: "2001-02-02" }
    ])
    db.players.find( { $where: function() {
      return (hex_md5(this.name) == "9b53e667f30cd329dca1ec9e6a83e994")
    } } );
    // {
    //    "_id" : 2,
    //    "name" : "Anya",
    //    "username" : "anya",
    //    "first_login" : "2001-02-02"
    // }
    
  • $expr
    從官網看這篇的時候,會突然資訊量爆棚一堆英文單字,expression / aggregation / stage / pipeline …
    其實可專注在,如何分辨使用 $expr / aggregate 這件事

    // 這是使用 aggregate 起手式
    db.collection.aggregate()
    // 這是使用 $expr 起手式
    db.collection<User>("user").find({ $expr: ... })
    

    stage / pipeline 曾經做過 CI/CD 或 webpack 優化 的過程中可以看到這英文單字,中文來說就是「階段
    expression 就是在描述「條件
    $expr 的條件中可以用聚合表達式查詢功能,下方為官網範例。

    db.supplies.insertMany([
     { "_id" : 1, "item" : "binder", "qty" : NumberInt("100"), "price" : NumberDecimal("12") },
     { "_id" : 2, "item" : "notebook", "qty" : NumberInt("200"), "price" : NumberDecimal("8") },
     { "_id" : 3, "item" : "pencil", "qty" : NumberInt("50"), "price" : NumberDecimal("6") },
     { "_id" : 4, "item" : "eraser", "qty" : NumberInt("150"), "price" : NumberDecimal("3") },
     { "_id" : 5, "item" : "legal pad", "qty" : NumberInt("42"), "price" : NumberDecimal("10") }
    ])
    
    // 使用聚合表達式查詢
    let discountedPrice = {
      $cond: {
          if: { $gte: ["$qty", 100] },
          then: { $multiply: ["$price", NumberDecimal("0.50")] },
          else: { $multiply: ["$price", NumberDecimal("0.75")] }
      }
    };
    
    db.supplies.find( { $expr: { $lt:[ discountedPrice,  NumberDecimal("5") ] } });
    
  • $jsonSchema 略,目前感覺用不到

數組查詢 (Array Query)

運算符翻譯格式
$all符合這些條件的資料{ : { $all: [ , … ] } }
$size陣列內數量相符 [1,2] => $size: 2{ field: { $size: size } }

總結

查詢為DB超級常見的功能,初期簡易使用即可,可專研 Evaluation Query,若是要更彈性使用,可後續網 aggregation篇章深入,官網資訊量很多

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus