MongoDB 4.X CRUD基本操作

本文總結了MongoDB 4.X在mongo shell客戶端涉及的對文檔一些基本的增刪改查操作,即CRUD操作。主要結合了自己平時使用MongoDB的操作命令,更詳細的命令可以參考官方文檔: https://docs.mongodb.com/manual/crud/

創建(Create Operations)

創建(Create Operations)也叫插入操作,當集合不存在時,插入操作同時也會創建集合。MongoDB提供以下幾種插入文檔方法:

  • db.collection.insert():在指定集合中插入單個或多個文檔。
  • db.collection.insertOne():在指定集合中插入單個文檔(版本3.2新增)。
  • db.collection.insertMany():在指定集合中插入多個文檔(版本3.2新增)。

db.collection.insert()

在平時的使用當中,db.collection.insert()是我用得最多的文檔插入方式,具體的語法格式如下:

db.collection.insert(
   <document or array of documents>,
   {
     writeConcern: <document>,
     ordered: <boolean>
   }
)

參數說明:

  • document:指定一個或多個文檔;
  • writeConcern:文檔寫入確認級別(可選),關於讀寫策略確認級別,以後再進行討論;
  • ordered:指定文檔是否按順序插入(可選),默認為true;
    • 當指定為true時,插入多個文檔時將文檔排序保存在一個數組中進行插入,如果其中有一個文檔插入失敗,則會導致數組中餘下的文檔不進行插入操作;
    • 當指定為false時,插入多個文檔時將文檔不進行排序保存在一個數組中進行插入,如果其中有一個文檔插入失敗,則不影響數組中餘下的文檔進行插入操作。

如果插入的文檔當中沒有指定_id字段,則MongoDB會自動為文檔生成具有唯一ObjectId值的字段_id

使用示例:

// 沒有指定_id字段的插入單個文檔
db.products.insert( { item: "card", qty: 15 } );

// 指定_id字段的插入單個文檔
db.products.insert( { _id: 10, item: "box", qty: 20 } );

// 插入多個文檔,不進行排序,多個文檔包含在數組[]中
db.products.insert(
   [
     { _id: 11, item: "pencil", qty: 50, type: "no.2" },
     { item: "pen", qty: 20 },
     { item: "eraser", qty: 25 }
   ]
);

// 插入多個文檔,並進行排序
db.products.insert(
   [
     { _id: 20, item: "lamp", qty: 50, type: "desk" },
     { _id: 21, item: "lamp", qty: 20, type: "floor" },
     { _id: 22, item: "bulk", qty: 100 }
   ],
   { ordered: false }
);

db.collection.insertOne()

語法格式如下:

db.collection.insertOne(
   <document>,
   {
      writeConcern: <document>
   }
)

參數說明:

參考db.collection.insert()的參數說明。

使用示例:

// 單行插入文檔,關於_id字段指定與否也與db.collection.insert()一致
db.products.insertOne( { item: "card", qty: 15 } );

db.collection.insertMany()

語法格式如下:

db.collection.insertMany(
   [ <document 1> , <document 2>, ... ],
   {
      writeConcern: <document>,
      ordered: <boolean>
   }
)

參數說明:

參考db.collection.insert()的參數說明。

使用示例:

參考db.collection.insert()的參數說明。

關於返回確認信息

db.collection.insert()在插入文檔成功之後返回的信息相對較為簡潔:

db.products.insert( { item: "card", qty: 15 } );
WriteResult({ "nInserted" : 1, "writeConcernError" : [ ] })

db.collection.insertOne()db.collection.insertMany()返回的信息較為詳細:

db.products.insertOne( { item: "card", qty: 15 } );
{
    "acknowledged": true,
    "insertedId": ObjectId("5eccbd214139000074003be8")
}

db.products.insertMany( [
      { _id: 10, item: "large box", qty: 20 },
      { _id: 11, item: "small box", qty: 55 },
      { _id: 12, item: "medium box", qty: 30 }
   ] );
{
    "acknowledged": true,
    "insertedIds": [
        10,
        11,
        12
    ]
}

查詢(Read Operations)

查詢(Read Operations)讀操作,是對集合中已存在的文檔進行查詢,即對應關係型數據庫當中的select操作,比如MySQL,MongoDB提供以下幾種主要查詢文檔方法:

  • db.collection.find():查詢指定集合中滿足條件的一個或多個文檔和視圖;
  • db.collection.findOne():查詢指定集合中滿足條件的第一個文檔,並以格式化方式展現,通過pretty()方法。

來自官方文檔的測試數據:

db.inventory.insertMany([
   { item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
   { item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" },
   { item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },
   { item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },
   { item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" }
]);

db.collection.find()

db.collection.find()可以說是使用頻率最高的方法了,可以用來查詢數據庫集合當中的文檔。

語法格式如下:

db.collection.find(<query>, <projection>)
  • query:查詢表達式;
  • projection:指定查詢結果集中需要显示的字段。
    • Col_name:1|true 代表显示該字段;
    • Col_name:0 | false 代表不显示該字段。

_id字段是默認显示的,如果不想显示,則顯式指定{"_id" : 0}

查詢所有文檔:

db.inventory.find()

db.inventory.find({})

db.collection.findOne()

db.collection.findOne()方法显示符合條件查詢的第一條文檔,接受的參數與db.collection.find()方法一致。

條件查詢操作符

通常對文檔的查詢,是需要帶條件的,而很少使用到不帶條件的全文檔檢索,以下總結了幾種常使用的查詢操作符:

比較操作符

比較操作符涉及的操作如下錶所示:

名稱 說明
$eq 與指定值相等
$gt 大於指定的值
$gte 大於或等於指定的值
$in 指定的值在數組中
$lt 小於指定的值
$lte 小於或等於指定的值
$ne 所有不等於指定的值
$nin 指定的值不在數組中

使用示例:

// $eq:等值查詢 SQL: SELECT * FROM inventory WHERE status = "D";
db.inventory.find( { status: "D" } )

// $ne 同$eq

// $gt:範圍查詢(以大於為例) SQL: SELECT * FROM inventory WHERE qty > 30;
db.inventory.find( { qty: { $gt: 30 } } )

// $gte、$lt、$lte 同$gt

// $in:或查詢,可使用or代替 SQL: SELECT * FROM inventory WHERE status in ("A", "D")
db.inventory.find( { status: { $in: [ "A", "D" ] } } )

// $nin 同$in

邏輯操作符

邏輯操作符涉及的操作如下錶所示:

名稱 說明
$and 指定查詢同時滿足多個條件查詢子句
$not 指定查詢不滿足條件查詢子句
$nor 指定查詢無法滿足多個條件查詢子句
$or 指定查詢滿足其中某個條件查詢子句

使用示例:

// $and: 邏輯與查詢 SQL: SELECT * FROM inventory WHERE status = "A" AND qty < 30;
db.inventory.find( { $and: [ { status: { $eq: "A" },  qty: { $lt: 30 } } ] } )

// $not: 不符合查詢 SQL: SELECT * FROM inventory WHERE status <> "A";
db.inventory.find( { status: { $not: { $eq: "A" } } } )

/*
$nor: 無法同時滿足多個條件查詢,字段不存在時也符合 SQL: SELECT * FROM inventory WHERE status <> "A" AND qty > 30; 
符合以下條件之一都會出現在結果集中:
1.文檔包含status和qty字段並且符合條件;
2.文檔包含status字段並且符合條件,不包含qty字段;
3.文檔不包含status字段,包含qty字段並且符合條件;
4.文檔不包含status字段和qty字段。
*/
db.inventory.find( { $nor: [ { status: { $eq: "A" } },  { qty: { $lt: 30 } } ] } )

// $or: 邏輯或查詢 SQL: SELECT * FROM inventory WHERE status = "A" OR qty < 30;
db.inventory.find( { $or: [ { status: "A" }, { qty: { $lt: 30 } } ] } )

元素操作符

元素操作符主要涉及的操作如下錶所示:

名稱 說明
$exists 指定查詢文檔是否有對應的字段
$type 指定查詢文檔的某個字段是否是對應類型

使用示例:

// $exists: 是否存在指定字段查詢
db.inventory.find( { price: { $exists: true } } )

// $type: 字段是否是指定類型查詢
db.inventory.find( { "qty": { $type: "double" } } )

評估操作符

評估操作符主要涉及的操作如下錶所示,更多操作符可以參考官方文檔:https://docs.mongodb.com/manual/reference/operator/query-evaluation/

名稱 說明
$expr 為同一個文檔中的字段指定表達式並且符合條件的查詢,比如比較同一文檔當中兩個字段的值
$mod 為字段值取模並且符合條件的查詢

為了更好的使用這兩個主要的操作符,額外創建個文檔:

db.monthlyBudget.insertMany([
    { "_id" : 1, "category" : "food", "budget": 400, "spent": 450 },
    { "_id" : 2, "category" : "drinks", "budget": 100, "spent": 150 },
    { "_id" : 3, "category" : "clothes", "budget": 100, "spent": 50 },
    { "_id" : 4, "category" : "misc", "budget": 500, "spent": 300 },
    { "_id" : 5, "category" : "travel", "budget": 200, "spent": 650 }
]);

使用示例:

// $expr: 允許使用聚合表達式,這裏以$gt為例,更多表達式參考 https://docs.mongodb.com/manual/meta/aggregation-quick-reference/#aggregation-expressions
db.monthlyBudget.find( { $expr: { $gt: [ "$spent" , "$budget" ] } } )

// $mod: 對字段所在值進行取模運算,显示符合條件的查詢,如qty字段值對4取模,並且餘數為0
db.inventory.find( { qty: { $mod: [ 4, 0 ] } } )

更新(Update Operations)

更新(Update Operations)是對已存在的文檔進行修改操作,MongoDB提供以下幾種主要更新文檔方法:

  • db.collection.update():更新或替換集合中符合條件的一個或多個文檔;
  • db.collection.updateOne():只更新集合中符合條件的第一個文檔,即使有多個文檔(版本3.2新增);
  • db.collection.updateMany():更新集合中所有符合條件的文檔(版本3.2新增)。

db.collection.update()

根據update指定的表達式可以修改文檔中符合條件的字段或代替整個文檔。具體的語法格式如下:

db.collection.update(
   <query>,   //查詢表達式
   <update>,  //更新表達式
   {
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>,
     collation: <document>,
     arrayFilters: [ <filterdocument1>, ... ],
     hint:  <document|string>                   // 版本4.2新增
   }
)

參數說明:

  • query:更新文檔的查詢表達式;如果指定了參數upsert: true並且集合中沒有符合查詢條件的文檔,查詢條件中有關於字段_id指定了.分隔符的,並不會插入新的文檔;

  • update:主要包含三種格式

    • 1.更新文檔:只包含更新操作符表達式;
    • 2.替換文檔:只包含<field1>: <value1>對;
    • 3.聚合管道:版本4.2新增,詳細參考官方文檔。
  • upsert:當query查詢條件沒符合更新的文檔,就新創建文檔(可選),默認值為false

  • multi:是否更新多個符合條件的文檔(可選),默認值為false,只更新符合條件的第一個文檔;

  • writeConcern:參考db.collection.insert()相同參數說明;

  • collation:指定校對規則(可選,版本3.4新增);

  • arrayFilters:文檔數組更新過濾操作符(可選,版本3.6新增);

    詳細參考:https://docs.mongodb.com/manual/reference/method/db.collection.update/#specify-arrayfilters-for-array-update-operations

  • hint:採用文檔或字符串的形式指定適用於查詢表達式的索引,如果索引不存在則報錯(可選,版本4.2新增)。

使用示例:

使用示例將通過使用兩種場景進行,一是沒有使用參數選項upsert,二是使用參數選項upsert

  • 不使用選項upsert
// 測試數據
db.books.remove({});

db.books.insertMany([
  {
    "_id" : 1,
    "item" : "TBD",
    "stock" : 0,
    "info" : { "publisher" : "1111", "pages" : 430 },
    "tags" : [ "technology", "computer" ],
    "ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "lmn", "rating" : 5 } ],
    "reorder" : false
   },
   {
    "_id" : 2,
    "item" : "XYZ123",
    "stock" : 15,
    "info" : { "publisher" : "5555", "pages" : 150 },
    "tags" : [ ],
    "ratings" : [ { "by" : "xyz", "rating" : 5 } ],
    "reorder" : false
   }
]);


/* 使用選項參數 upsert: true
1、如果查詢表達式找到匹配的文檔,則執行更新操作;
2、如果查詢表達式沒有找到匹配的文檔,則執行插入操作;
*/
db.books.update(
   { item: "ZZZ135" },   // 查詢表達式
   {                     // 更新或替換文檔
     item: "ZZZ135",
     stock: 5,
     tags: [ "database" ]
   },
   { upsert: true }
);

// 1.使用更新操作表達式
/* $set操作符
1、查詢表達式指定需要更新的文檔 _id;
2、$inc操作符: stock的字段值+5;
3、$set操作符: 替換item字段值,替換嵌入文檔info的publisher字段值,替換tags字段值,替換數組ratings的第二個元素值
*/
db.books.update(
   { _id: 1 },
   {
     $inc: { stock: 5 },
     $set: {
       item: "ABC123",
       "info.publisher": "2222",
       tags: [ "software" ],
       "ratings.1": { by: "xyz", rating: 3 }
     }
   }
);
更新之後的文檔:
{

  "_id" : 1,
  "item" : "ABC123",
  "stock" : 5,
  "info" : { "publisher" : "2222", "pages" : 430 },
  "tags" : [ "software" ],
  "ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "xyz", "rating" : 3 } ],
  "reorder" : false
}

// 2.為已存在的數組添加元素
// $push操作符: 為指定文檔數組ratings添加一個元素
db.books.update(
   { _id: 2 },
   {
     $push: { ratings: { "by" : "jkl", "rating" : 2 } }
   }
);
更新之後的文檔:
{
  "_id" : 2,
  "item" : "XYZ123",
  "stock" : 15,
  "info" : {
   "publisher" : "5555",
   "pages" : 150
  },
  "tags" : [ ],
  "ratings" : [
   { "by" : "xyz", "rating" : 5 },

   { "by" : "jkl", "rating" : 2 }

  ],
  "reorder" : false
 }

// 3.文檔移除字段
// $unset操作符: 移除文檔的指定字段,為_id:1文檔移除tags字段
db.books.update( { _id: 1 }, { $unset: { tags: 1 } } );
更新后的文檔:
{
  "_id" : 1,
  "item" : "TBD",
  "stock" : 0,
  "info" : {
   "publisher" : "1111",
   "pages" : 430
  },
  "ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "lmn", "rating" : 5 } ],
  "reorder" : false
 }

// 4.替換整個文檔
// 替換_id:2的文檔
db.books.update(
   { _id: 2 },
   {
     item: "XYZ123",
     stock: 10,
     info: { publisher: "2255", pages: 150 },
     tags: [ "baking", "cooking" ]
   }
);
更新后的文檔:
{
   "_id" : 2,
   "item" : "XYZ123",
   "stock" : 10,
   "info" : { "publisher" : "2255", "pages" : 150 },
   "tags" : [ "baking", "cooking" ]
}

// 5.更新多個文檔
db.books.update(
   { stock: { $lte: 10 } },
   { $set: { reorder: true } },
   { multi: true }
);
更新后的全部文檔:
[
  {
    "_id" : 1,
    "item" : "ABC123",
    "stock" : 5,
    "info" : {
     "publisher" : "2222",
     "pages" : 430
    },
    "ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "xyz", "rating" : 3 } ],

    "reorder" : true

   }
   {
     "_id" : 2,
     "item" : "XYZ123",
     "stock" : 10,
     "info" : { "publisher" : "2255", "pages" : 150 },
     "tags" : [ "baking", "cooking" ],

     "reorder" : true

   }
]
  • 使用upserts選項
/* 使用選項參數 upsert: true
1、如果查詢表達式找到匹配的文檔,則執行更新操作;
2、如果查詢表達式沒有找到匹配的文檔,則執行插入操作;
*/

// 1.插入未符合更新條件的文檔
db.books.update(
   { item: "ZZZ135" },   
   {                     
     item: "ZZZ135",
     stock: 5,
     tags: [ "database" ]
   },

   { upsert: true }      

);
因為集合併未滿足條件的文檔,則插入的文檔為:
{
  "_id" : ObjectId("5da78973835b2f1c75347a83"),
  "item" : "ZZZ135",
  "stock" : 5,
  "tags" : [ "database" ]
}

// 2.插入未符合更新條件並且基於更新操作符的文檔
// 如果沒有符合更新查詢條件,並且使用的是更新操作符,則會基於當前的查詢條件和更新操作符字段插入新的文檔
db.books.update(
   { item: "BLP921" },   
   {                     
      $set: { reorder: false },
      $setOnInsert: { stock: 10 }
   },
   { upsert: true }      
);
新插入的文檔為:
{
  "_id" : ObjectId("5da79019835b2f1c75348a0a"),
  "item" : "BLP921",
  "reorder" : false,
  "stock" : 10
}

// 3.插入未符合更新條件並且基於聚合管道的文檔
// 關於聚合管道請參考官方文檔:https://docs.mongodb.com/manual/reference/method/db.collection.update/#update-with-aggregation-pipeline

// 4.插入未符合更新條件並且同時聯合多文檔操作符的文檔
如果不符合查詢條件,則只會插入單個文檔
db.books.update(
  { "info.publisher": "Self-Published" },   
  {                                         
    $set: { reorder: false, tags: [ "literature", "hardcover" ], stock: 25 }
  },
  { upsert: true, multi: true }             
);
新插入的文檔:
{
  "_id" : ObjectId("5db337934f670d584b6ca8e0"),
  "info" : { "publisher" : "Self-Published" },
  "reorder" : false,
  "stock" : 25,
  "tags" : [ "literature", "hardcover" ]
}

db.collection.updateOne()

根據update指定的參數可以修改文檔中符合條件的字段或代替整個文檔,與db.collection.update()不同的是每次只更新單個文檔。

語法格式如下:

db.collection.updateOne(
   <filter>,
   <update>,
   {
     upsert: <boolean>,
     writeConcern: <document>,
     collation: <document>,
     arrayFilters: [ <filterdocument1>, ... ],
     hint:  <document|string>        
   }
)

參數說明:

參考db.collection.update()的參數說明。

使用示例:

// 參考db.collection.update()

db.collection.updateMany()

根據update指定的參數可以修改文檔中符合條件的字段或代替整個文檔,與db.collection.updateOne()不同的是更新所有符合條件的文檔。

語法格式如下:

db.collection.updateMany(
   <filter>,
   <update>,
   {
     upsert: <boolean>,
     writeConcern: <document>,
     collation: <document>,
     arrayFilters: [ <filterdocument1>, ... ],
     hint:  <document|string>        
   }
)

參數說明:

參考db.collection.update()的參數說明。

使用示例:

// 參考db.collection.update()

刪除(Delete Operations)

刪除是指對集合當中已存在的文檔進行清除操作,MongoDB提供以下幾種主要刪除文檔方法:

  • db.collection.deleteOne():只刪除集合中符合條件的一個文檔;
  • db.collection.deleteMany():刪除集合中所有符合條件的文檔;
  • db.collection.remove():刪除集合中符合條件的一個或多個文檔。

db.collection.deleteOne()

根據filter選項條件刪除集合中的單個文檔,具體語法格式如下:

db.collection.deleteOne(
   <filter>,
   {
      writeConcern: <document>,
      collation: <document>
   }
)

參數說明:

  • filter:指定基於查詢表達式的過濾條件,關於查詢表達式可以查看db.collecion.find()中的<query>
  • writeConcern:參考db.collection.insert()相同參數說明;
  • collation:指定校對規則(可選,版本3.4新增);

使用示例:

// 刪除指定條件的單個文檔
db.orders.deleteOne( { "_id" : 1 } );
{ "acknowledged" : true, "deletedCount" : 1 }

db.collection.deleteMany()

根據filter選項條件刪除集合中的單個文檔,具體語法格式如下:

db.collection.deleteMany(
   <filter>,
   {
      writeConcern: <document>,
      collation: <document>
   }
)

參數說明:

參考db.collection.deleteOne()的參數說明。

使用示例:

// 刪除指定條件的多個文檔
db.orders.deleteMany( {"cust_id" : "Cam Elot"} );
{ "acknowledged" : true, "deletedCount" : 2 }

注意: 如果是對固定集合進行刪除文檔操作則會報錯,固定集合的清除操作使用方法db.collection.drop()

總結

  1. 本文簡單梳理了在Mongo Shell下基本的CRUD操作,主要適用於DBA的運維管理,如果是研發同學,根據不同的編程語言使用不同客戶端驅動進行操作,詳細同樣可以參考官方文檔;
  2. 針對CRUD各個方面還有其他一些額外的方法,比如查詢修改文檔方法db.collection.findAndModify(),這裏只是總結每個文檔操作中一些最基礎的方法,對於額外高級的方法這裏不再贅述;
  3. 掌握了這些基本的CRUD操作,就可以對MongoDB文檔進行操作了,但還是需要控制好權限,畢竟數據安全不是小事,做變更之前做好數據的備份,以防萬一。

參考

https://docs.mongodb.com/manual/crud/

https://docs.mongodb.com/manual/reference/operator/query-evaluation/

https://docs.mongodb.com/manual/reference/method/db.collection.update/#specify-arrayfilters-for-array-update-operations

https://docs.mongodb.com/manual/reference/method/db.collection.update/#update-with-aggregation-pipeline

〖本人水平有限,文中如有錯誤還請留言批評指正!〗

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

※教你寫出一流的銷售文案?

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

您可能也會喜歡…