跳至主要内容

資料結構與關聯:文件如何結構化

Resetting Your Database

刪除資料庫

步驟一:先切換至欲刪除的資料庫
$ use dbName

步驟二:輸入刪除指令
$ db.dropDatabase()

刪除 Collection

步驟一:先確認目前有哪些 Collection
$ show collections

步驟二:輸入刪除指令
$ db.collectionName.drop()

Structuring Documents

以下列出 MongoDB 可接受的三種資料結構

雜亂無章

實務上不會這樣儲存資料
[
{
"name": "Apple",
"price": 2
},
{
"title": "Box",
"currency": "USD"
},
{
"name": "Jack",
"isAdmin": true
}
]

結構相同

如 SQL 般井然有序的資料結構
[
{
"name": "Apple",
"price": 2.25,
"discount": null
},
{
"name": "Box",
"price": 3.99,
"discount": false
},
{
"name": "Car",
"price": 99999,
"discount": true
}
]

保有彈性

井然有序但允許例外(如 line 13)
[
{
"name": "Apple",
"price": 2.25
},
{
"name": "Box",
"price": 3.99
},
{
"name": "Car",
"price": 99999,
"discount": true
}
]

Data Types - An Overview

MongoDB 的資料型別

  • Text
    使用上沒什麼限制,最高容量為 16 MB。
  • Boolean
  • Number
    細分為 int32、int64、decimal
  • ObjectId
    基於 timestamp 而自動生成的 ID,因此同一批次寫入的資料會是連號 ID。
  • ISODate
    ISODate("2020-02-02")
  • Timestamp
    Timestamp(11421532)
  • Embedded Document
  • Array
  • Number in mongosh 在 Node.js Driver 的 mongosh 當中,數字皆以 float64 存取。

Data Types in Action

在 mongosh 當中可使用 Driver 對應的語言的各種函式,詳情可參考官方文件。

mongosh 使用 JavaScript 的 new Date() 及 new Timestamp()
$ db.companies.insertOne({foundingDate: new Date(), insertedAt: new Timestamp()})

mongosh Methods

在 mongosh 當中有許多方法可使用,點擊標題連結可檢視官方文件說明。

  • db.stats()
    這個方法可以檢視資料庫的統計資料(statistics)。
db.stats() 輸出結果範例
{
db: 'numbers',
collections: 1,
views: 0,
objects: 1,
avgObjSize: 29,
dataSize: 29,
storageSize: 20480,
indexes: 1,
indexSize: 20480,
totalSize: 40960,
scaleFactor: 1,
fsUsedSize: 58829078528,
fsTotalSize: 250685575168,
ok: 1
}
  • NumberInt()
    NumberInt() 用於插入資料時,如此將以 int32 的型別插入數值。
NumberInt() 使用範例
$ db.collection_name.insertOne({a: NumberInt(1)})
  • typeof
    使用 typeof 可確認資料型別
typeof 使用範例
$ typeof db.collection_name.findOne({key: value}).key

Data Types & Limits

值得注意的資料型別限制

  • 普通整數(int32)
    可儲存範圍為 +-2,147,483,647
  • 長整數(int64)
    可儲存範圍為 +-9,223,372,036,854,775,807
  • 文字(text)
    長度不限,但容量不得超過 Document 上限(16MB)

在 mongosh 當中

NumberInt 建立 int32 數值 => NumberInt(55) NumberLong 建立 int64 數值 => NumberLong(7489729384792)

由於 shell 以 JavaScript 為基礎,而 JavaScript 只有浮點數及倍精度數值,不區分整數及浮點數, 因此插入資料時如果只填入數字(例如 insertOne({a: 1}),該數字將以普通的浮點數儲存至資料庫。

NumberDecimal 可建立高精度浮點數值 => NumberDecimal("12.99")
此方法適用於極度講求精確度的計算。

使用 MongoDB 驅動程式(而非 shell)編寫應用程式時(例如 PHP、.NET、Node.js 等)時,
可以使用驅動程式建立上述特殊數值。

以 Node.js 為例:http://mongodb.github.io/node-mongodb-native/3.1/api/Long.html

以下是透過驅動程式建立 NumberLong 值的範例:

const Long = require("mongodb").Long;

db.collection("wealth").insert({
value: Long.fromString("121949898291"),
});

檢視各驅動程序的 API 文件,可找到建立 int32、int64 等數值的方法。

How to Derive your Data Structure - Requirements

示意圖:如何設計資料結構

Using "lookUp()" for Merging Reference Relations

Adding Collection Document Validation

使用 createCollection 方法及 $jsonSchema 可建立含有資料驗證的 Collection,
其使用方法見下列官方文件。

以下指令可檢視 Collection 有何資料驗證設定

$ db.getCollectionInfos({name:"collection_name"})

Changing the Validation Action

使用 runCommand 方法及 collMod 可修改 Collection 的資料驗證規則,
其使用方法見下列官方文件。

runCommand 範例
db.runCommand({
collMod: "collection_name",
validator: {
$jsonSchema: {
// add schema
},
/*
validationAction option, which determines whether MongoDB should error and reject
documents that violate the validation rules or warn about the violations in
the log but allow invalid documents.
*/
validationAction: "warn",
},
});

Wrap Up

資料結構的設計考量

  • In which format will you fetch your data?
    根據讀取或寫入的需求設計資料結構
  • How often will you fetch and change your data?
    思考讀取或寫入的頻率、何者更應該優化
    如果經常寫入資料,應該避免資料重複。
    如果資料不常更動,且經常讀取,或可允許少量重複。
  • How much data will you save (and how big is it)?
    嵌入式結構不適合儲存海量資料
  • How is your data related?
    從一對一、一對多、多對多思考是否使用嵌入式結構
  • Will duplicates hurt you ( => many updates)?
    如果資料需要頻繁更新,該資料應避免重複。
    如果重複的資料不需全面同步更新,或許可以允許資料重複。(例如 snapshot data)
  • Will you hit data / storage limits?