4.3.2 Collection.find()

find(SearchConditionStr) 函數用於搜尋集合中的文件,類似於 SQL 資料庫的 SELECT 陳述式。它採用搜尋條件字串 (SearchConditionStr) 作為參數,以指定應從資料庫傳回的文件。execute() 函數會觸發 find() 操作的實際執行。

SearchConditionStr 可以是下列其中一種形式

  • 如果未指定 SearchConditionStr,則 find() 操作會傳回集合中的所有文件。

    // Get a collection
    var myColl = session.getSchema("world_x").getCollection("countryinfo");
    // To return all documents in world_x: 
    myColl.find().execute();
  • SearchConditionStr 最常見的形式是

    JSON-path [ operator { value | JSON-path} ]

    以下針對 SearchConditionStr 的不同部分進行說明

    • JSON-path:JSON 路徑識別 JSON 文件中的元素;如需詳細資料,請參閱 JSON 路徑語法。以下簡要概述 JSON 路徑語法

      • JSON 路徑以範圍開始:在 MySQL 的 JSON 文件實作中,路徑的範圍永遠是正在操作的文件,表示為 $,它永遠是隱含假設的,因此在大多數情況下可以省略;例如,路徑 $.geography.Region 等同於 geography.Region

        注意

        在某些情況下,無法省略 $;例如

        • 當使用 ** 萬用字元時 (例如,find("$**.b1");請參閱以下關於萬用字元的討論),

        • 當 JSON 路徑僅包含文字字串時,如果省略 $ (例如,find("$.'country_name'") 用於尋找所有具有 country name 欄位的文件)。

      • 在範圍之後,路徑由一個或多個路徑分支組成。路徑分支從 JSON 樹的一個層級向下導引至下一層,且連續的路徑以句點 (.) 分隔。例如:myColl.find("geography.Continent = 'Africa'") 會尋找所有在 geography 欄位下,Continent 欄位的值為 Africa 的文件。

      • 陣列中的元素由 [N] 表示,其中 N 是陣列索引,必須為非負整數。

        myColl.add({ name:'John', favorNums: [1, 3, 5, 7, 9] }).execute();
        myColl.find("favorNums[0] = 1").execute(); //Returns the document just added
        }
    • 萬用字元符號 *** 可在 JSON 路徑中依下列方式使用

      • object.* 代表成員 object 下所有成員的值。例如,在範例 world_x 綱要中的 countryinfo 集合中, geography.* 代表物件 geography 下的所有成員,且 myColl.find("'Africa' in geography.*") 會傳回所有在 geography 下的任何成員中具有值 Africa 的文件。

      • array[*] 代表陣列中所有元素的值。例如

        myColl.add({ name:'John', favorNums: [1, 3, 5, 7, 9] }).execute();
        myColl.add({ name:'Jane', favorNums: [2, 4, 6, 8, 10] }).execute();
        myColl.find("1 in favorNums[*]").execute(); //Returns the first document added above
        myColl.find("2 in favorNums[*]").execute(); //Returns the second document added above
        }
      • [prefix]**suffix 代表在文件 prefix 下,以 suffix 結尾的所有路徑,不論路徑的深度為何。下列範例說明如何使用 ** 來傳回不同的結果

        mysql-js> myColl.find().execute();
        {
            "a": "bar",
            "b": {
                "b1": 6,
                "b2": 7,
                "b3": {
                    "b1": 99,
                    "b2": 98,
                    "b3": {
                        "b1": 999,
                        "b2": 998
                    }
                }
            },
            "_id": "000061313aa10000000000000001"
        }
        {
            "a": "baz",
            "b": {
                "b1": 1,
                "b2": 7
            },
            "_id": "000061313aa10000000000000002"
        }
        {
            "a": "bbr",
            "c": 37,
            "_id": "0000613247ed0000000000000001"
        }
        3 documents in set (0.0007 sec)
        mysql-js> myColl.find("$**.b2").execute();
        {
            "a": "bar",
            "b": {
                "b1": 6,
                "b2": 7,
                "b3": {
                    "b1": 99,
                    "b2": 98,
                    "b3": {
                        "b1": 999,
                        "b2": 998
                    }
                }
            },
            "_id": "000061313aa10000000000000001"
        }
        {
            "a": "baz",
            "b": {
                "b1": 1,
                "b2": 7
            },
            "_id": "000061313aa10000000000000002"
        }
        2 documents in set, 1 warning (0.0008 sec)
        ...
        mysql-js> myColl.find("$**.b3**.b2").execute();
        {
            "a": "bar",
            "b": {
                "b1": 6,
                "b2": 7,
                "b3": {
                    "b1": 99,
                    "b2": 98,
                    "b3": {
                        "b1": 999,
                        "b2": 998
                    }
                }
            },
            "_id": "000061313aa10000000000000001"
        }
        1 document in set, 1 warning (0.0011 sec)
        ...

        使用 ** 萬用字元時,適用下列需求

        • prefix 應為 $ 或本身為文件的元素。

        • suffix 應為路徑分支,且永遠為必要項目 (也就是說,路徑運算式不得以 ** 結尾)。

        • 路徑運算式不得包含序列 ***

    • value 是要與 JSON-path 上的元素進行比較的值。萬用字元 %_ 可以與 LIKE 運算子一起在 value 中使用,就像在 MySQL WHERE 子句中一樣。例如

      myColl.find("Name LIKE 'Austra%'")
      myColl.find("geography.Continent LIKE 'Asi_'")
    • operator:下列運算子可用於 SearchConditionStr 中:OR (||)AND (&&)XORISNOTBETWEENINLIKEOVERLAPS!=<>>>=<<=&|<<>>+-*/~%。以下是一些使用運算子的範例

      myColl.find("Name = 'Australia'")
      myColl.find("demographics.Population >= 1000000" )
      myColl.find("demographics.LifeExpectancy BETWEEN 50  AND 60")
      myColl.find("government.HeadOfState = 'Elizabeth II' AND geography.Region = 'Caribbean'")

      如果未提供運算子和後續 JSON 路徑,find() 會傳回所有所提供 JSON 路徑指向某些非 Null 元素的文件。例如

      myColl.find("demographics.Population" ).execute();

      傳回所有具有 demographics.Population 元素的文件

      {
          "GNP": 828,
          "_id": "00005de917d80000000000000000",
          "Code": "ABW",
          "Name": "Aruba",
          "IndepYear": null,
          "geography": {
              "Region": "Caribbean",
              "Continent": "North America",
              "SurfaceArea": 193
          },
          "government": {
              "HeadOfState": "Beatrix",
              "GovernmentForm": "Nonmetropolitan Territory of The Netherlands"
          },
          "demographics": {
              "Population": 103000,
              "LifeExpectancy": 78.4000015258789
          }
      }
      {
          "GNP": 5976,
          "_id": "00005de917d80000000000000001",
      ...
      232 documents in set, 1 warning (0.0013 sec)
      Warning (code 3986): Evaluating a JSON value in SQL boolean context does an implicit comparison against JSON integer 0;
      if this is not what you want, consider converting JSON to an SQL numeric type with JSON_VALUE RETURNING

      SearchConditionStr 中使用 IN 運算子,檢查萬用字元涵蓋的所有成員內是否有值

      mysql-js> myColl.find("$**.b1").execute();
      {
          "a": "bar",
          "b": {
              "b1": 6,
              "b2": 7,
              "b3": {
                  "b1": 99,
                  "b2": 98,
                  "b3": {
                      "b1": 999,
                      "b2": 998
                  }
              }
          },
          "_id": "000061313aa10000000000000001"
      }
      {
          "a": "baz",
          "b": {
              "b1": 1,
              "b2": 7
          },
          "_id": "000061313aa10000000000000002"
      }
      2 documents in set, 1 warning (0.0012 sec)
      ...
      mysql-js> myColl.find("99 IN $**.b1").execute();
      {
          "a": "bar",
          "b": {
              "b1": 6,
              "b2": 7,
              "b3": {
                  "b1": 99,
                  "b2": 98,
                  "b3": {
                      "b1": 999,
                      "b2": 998
                  }
              }
          },
          "_id": "000061313aa10000000000000001"
      }
      1 document in set (0.0016 sec)
      ...

      OVERLAPS 運算子會比較兩個 JSON 片段,如果兩個片段在任何鍵值組或陣列元素中有任何共通值,則會傳回 true (1)。例如

      mysql-js> myColl.find("list").execute();
      {
          "_id": "1",
          "list": [
              1,
              4
          ]
      }
      {
          "_id": "2",
          "list": [
              4,
              7
          ]
      }
      2 documents in set, 1 warning (0.0010 sec)
      mysql-js> myColl.find("[1,2,3] OVERLAPS $.list")
      {
          "_id": "1",
          "list": [
              1,
              4
          ]
      }
      1 document in set (0.0006 sec)

數個方法 (例如 fields()sort()limit()) 可以鏈結至 find() 函數,以進一步篩選結果。例如

myColl.find("Name LIKE 'Austra%'").fields("Code")
myColl.find("geography.Continent LIKE 'A%'").limit(10)

也支援使用 bind() 進行參數繫結。下列範例說明 bind()find() 的用法

# Use the collection 'my_collection'
myColl = db.get_collection('my_collection')

# Find a single document that has a field 'name' that starts with 'L'
docs = myColl.find('name like :param').limit(1).bind('param', 'L%').execute()

print(docs.fetch_one())

# Get all documents with a field 'name' that starts with 'L'
docs = myColl.find('name like :param').bind('param','L%').execute()

myDoc = docs.fetch_one()
while myDoc:
  print(myDoc)
  myDoc = docs.fetch_one()

另請參閱 CollectionFindFunction,以瞭解 EBNF 中 find() 的語法。