返回
Featured image of post MongoDB - 深入Update

MongoDB - 深入Update

MongoDB - 想更新?換到認不得(別

基本使用

updateOne - 部分內容單筆修改

const collection: Collection<User> = db.collection<User>("user");
const query = {
  name: 'Fred'
}
const update = {
    $set: { 
      name: "Jason" 
    }
}
await collection.updateOne(query, update);

replaceOne - 全部內容單筆替換

const collection: Collection<User> = db.collection<User>("user");
const query = {
  name: 'Fred'
}
const update = { 
  name: "Jason",
  age: 18,
  gender: "male"
}
await collection.replaceOne(query, update);

upsert - 找不到就新增

const collection: Collection<User> = db.collection<User>("user");
const query = {
  name: 'Fred'
}
const update = {
    $set: { 
      name: "Jason" 
    }
}
const option = {
  upsert: true  // 找不到就新增
}
await collection.updateOne(query, update, option);

updateMany - 部分內容多筆修改

採用 sample_mflix.moviescollection注入資料方法

import { MongoClient } from "mongodb";

// 將 uri 字符串替換為 MongoDB 部署的連接字符串。
const uri = "<connection string uri>";

const client = new MongoClient(uri);

enum Rating {
  G = "G",
  PG = "PG",
  PG_13 = "PG-13",
  R = "R",
  NR = "NOT RATED",
}

interface Movie {
  rated: Rating;
  random_review?: string;
}

async function run() {
  try {
    const database = client.db("sample_mflix");
    const movies = database.collection<Movie>("movies");
    const result = await movies.updateMany(
      { rated: Rating.G },
      {
        $set: {
          random_review: `看完後我${100 * Math.random()}% 滿意。`,
        },
      }
    );
    console.log(`Updated ${result.modifiedCount} documents`);
  } finally {
    await client.close();
  }
}
run().catch(console.dir);

單筆運算符

運算符翻譯格式
$currentDate值設定為當前日期,無論是日期還是時間戳{ $currentDate: { field1: typeSpecification1, … } }
$incUpdate + value{ $inc: { field1: amount1, field2: amount2, … } }
$minUpdate < value{ $min: { field1: value1, … } }
$maxUpdate > value{ $max: { field1: value1, … } }
$mulUpdate * value{ $mul: { field1: number1, … } }
$rename欄位換名稱{$rename: { field1: newName1,field2: newName2,…}}
$set重設定 value{$set: { field1: value1, … } }
$setOnInsert重新設定 doc 原先設定的欄位update(query,{$setOnInsert: { field1: value1, … } },{ upsert: true })
$unset刪除指定欄位{$unset: {field1: “”, … } }

$currentDate

略,認為用不到

$inc

//  {
//    _id: 1,
//    sku: "abc123",
//    quantity: 10,
//    metrics: { orders: 2, ratings: 3.5 }
//  }
db.products.updateOne(
   { sku: "abc123" },
   { $inc: { quantity: -2, "metrics.orders": 1 } }
)
// retrun : 
// {
//   _id: 1,
//   sku: 'abc123',
//   quantity: 8, // 10 + -2 = 8
//   metrics: { orders: 3, ratings: 3.5 } // 2 + 1 = 3
// }

$min

/** 數字 **/
// { _id: 1, highScore: 800, lowScore: 200 }
db.scores.updateOne( { _id: 1 }, { $min: { lowScore: 150 } } )
// return
// { _id: 1, highScore: 800, lowScore: 150 } // 150 < 200 ,所以被替換了

/** 日期 **/
// { _id: 1, desc: "crafts", dateEntered: ISODate("2013-10-01T05:00:00Z") }
db.tags.updateOne( { _id: 1 }, { $min: { dateEntered: new Date("2013-09-25") } } )
// return
// { _id: 1, desc: "crafts", dateEntered: ISODate("2013-09-25T00:00:00Z") } // 2013-09-25 < 2013-10-01 ,所以被替換了

$max

// { _id: 1, highScore: 800, lowScore: 150 }
db.scores.updateOne( { _id: 1 }, { $max: { lowScore: 200 } } )
// return
// { _id: 1, highScore: 800, lowScore: 200 } // 200 > 150 ,所以被替換了

/** 日期 **/
// { _id: 1, desc: "crafts", dateEntered: ISODate("2013-09-25T05:00:00Z") }
db.tags.updateOne( { _id: 1 }, { $max: { dateEntered: new Date("2013-10-01") } } )
// return
// { _id: 1, desc: "crafts", dateEntered: ISODate("2013-10-01T00:00:00Z") } // 2013-10-01 > 2013-09-25,所以被替換了

$mul

//  { "_id" : 1, "item" : "Hats", "price" : Decimal128("10.99"), "quantity" : 25 }
db.products.updateOne(
   { _id: 1 },
   { $mul:
      { price: Decimal128( "1.25" ), quantity: 2}
   }
)
// retrun
// { _id: 1, item: 'Hats', price: Decimal128("13.7375"), quantity: 50 } // 10.99 * 1.25    25 * 2

$rename

// {
//   "_id": 1,
//   "alias": [ "The American Cincinnatus", "The American Fabius" ],
//   "mobile": "555-555-5555",
//   "nmae": { "first" : "george", "last" : "washington" }
// },
// {
//   "_id": 2,
//   "alias": [ "My dearest friend" ],
//   "mobile": "222-222-2222",
//   "nmae": { "first" : "abigail", "last" : "adams" }
// },
// {
//   "_id": 3,
//   "alias": [ "Amazing grace" ],
//   "mobile": "111-111-1111",
//   "nmae": { "first" : "grace", "last" : "hopper" }
// }
db.students.updateMany( {}, { $rename: { "nmae": "name" } } )
// return
// {
//   "_id": 1,
//   "alias": [ "The American Cincinnatus", "The American Fabius" ],
//   "mobile": "555-555-5555",
//   "name": { "first" : "george", "last" : "washington" }
// }

// {
//    "_id" : 2,
//    "alias" : [ "My dearest friend" ],
//    "mobile" : "222-222-2222",
//    "name" : { "first" : "abigail", "last" : "adams" }
// }

// { "_id" : 3,
//   "alias" : [ "Amazing grace" ],
//   "mobile" : "111-111-1111",
//   "name" : { "first" : "grace", "last" : "hopper" } }

$set

// {
//   _id: 100,
//   quantity: 250,
//   instock: true,
//   reorder: false,
//   details: { model: "14QQ", make: "Clothes Corp" },
//   tags: [ "apparel", "clothing" ],
//   ratings: [ { by: "Customer007", rating: 4 } ]
// }
db.products.updateOne(
   { _id: 100 },
   { $set:
      {
        quantity: 500,
        details: { model: "2600", make: "Fashionaires" },
        tags: [ "coats", "outerwear", "clothing" ]
      }
   }
)
// return 
// {
//   _id: 100,
//   quantity: 500,
//   instock: true,
//   reorder: false,
//   details: { model: '2600', make: 'Fashionaires' },
//   tags: [ 'coats', 'outerwear', 'clothing' ],
//   ratings: [ { by: 'Customer007', rating: 4 } ]
// }

$setOnInsert

略,認為用不到

$unset

// { "item": "chisel", "sku": "C001", "quantity": 4, "instock": true },
// { "item": "hammer", "sku": "unknown", "quantity": 3, "instock": true },
db.products.updateOne(
   { sku: "unknown" },
   { $unset: { quantity: "", instock: "" } }
)
// retrun
// { "item": "chisel", "sku": "C001", "quantity": 4, "instock": true },
// { "item": "hammer", "sku": "unknown" },

陣列運算符

運算符翻譯格式
$位置運算符{ “.$” : value }
$[]全部位置運算符{ update operator: { “array.$[]” : value } }
$[<identifier>]位置運算符{ update operator: { “array.$[identifier]” : value } },{ arrayFilters: [ { identifier: condition> } } ] }
$addToSet新增,重複不新增{$addToSet: { field1: value1, … } }
$pop移除 第一個 or 最後一個
$pull移除
$push新增,重複亦新增
$pullAll移除多個
interface Goods {
  name: string;
  tags?: string[];
}
interface Store {
  name: string;
  items: Goods[];
}
const collection: Collection<User> = db.collection<Store>("store");
// 先注入些資料
await collection.insertMany([
  {
    name: "肯德基",
    items: [
      {
        name: "炸雞",
        type: "炸物",
        tags: ["熱銷","好吃"],
      },
      {
        name: "薯條",
        type: "炸物",
      },
    ],
  },
  {
    name: "麥當勞",
    items: [
      {
        name: "炸雞",
        type: "炸物",
        tags: ["熱銷"],
      },
    ],
  },
]);

$

位置運算符
位置運算符

const query = { "items.type": "炸物" };
const update = {
  $push: { "items.$.tags": "當月熱銷" }
};
await collection.updateMany(query, update);

$[]

全部位置運算符
全部位置運算符

const query = { "items.type": "炸物" };
const update = {
  $push: { "items.$[].tags": "當月熱銷" }
};
await collection.updateMany(query, update);

$[<identifier>]

指定位置運算符
指定位置運算符

const query = { name: "肯德基" };
const update = {
  $push: { "items.$[i].tags": "當月熱銷" } 
};
const options = {
  arrayFilters: [
    {
      "i.name": "薯條",
    },
  ],
};
await collection.updateMany(query, update, options);

$addToSet

// { _id: 1, item: "polarizing_filter", tags: [ "electronics", "camera" ] }
db.inventory.updateOne(
   { _id: 1 },
   { $addToSet: { tags: "accessories" } }
)
// { _id: 1, item: "polarizing_filter", tags: [ "electronics", "camera", "accessories" ] } //沒有就新增
db.inventory.updateOne(
   { _id: 1 },
   { $addToSet: { tags: "camera" } }
)
// { _id: 1, item: "polarizing_filter", tags: [ "electronics", "camera", "accessories" ] } //不動,因為已有

/** 用 $each **/
// { _id: 2, item: "cable", tags: [ "electronics", "supplies" ] }
db.inventory.updateOne(
   { _id: 2 },
   { $addToSet: { tags: { $each: [ "camera", "electronics", "accessories" ] } } }
 )
// {
//   _id: 2,
//   item: "cable",
//   tags: [ "electronics", "supplies", "camera", "accessories" ] // "camera", "electronics" 已有,只添加 "accessories"
// }

$pop

// db.students.insertOne( { _id: 1, scores: [ 8, 9, 10 ] } )
db.students.updateOne( { _id: 1 }, { $pop: { scores: -1 } } )
// { _id: 1, scores: [ 9, 10 ] }  // -1 扣前面
db.students.updateOne( { _id: 1 }, { $pop: { scores: 1 } } )
// { _id: 1, scores: [ 9 ] }     // 1 扣後面

$pull

// {
//   _id: 1,
//   fruits: [ "apples", "pears", "oranges", "grapes", "bananas" ],
//   vegetables: [ "carrots", "celery", "squash", "carrots" ]
// },
// {
//   _id: 2,
//   fruits: [ "plums", "kiwis", "oranges", "bananas", "apples" ],
//   vegetables: [ "broccoli", "zucchini", "carrots", "onions" ]
// }
db.stores.updateMany(
    { },
    { $pull: { fruits: { $in: [ "apples", "oranges" ] }, vegetables: "carrots" } }
)
// {
//   _id: 1,
//   fruits: [ 'pears', 'grapes', 'bananas' ],   // 移除  "apples", "oranges" 
//   vegetables: [ 'celery', 'squash' ]          // 移除 "carrots"
// },
// {
//   _id: 2,
//   fruits: [ 'plums', 'kiwis', 'bananas' ],    // 移除  "apples", "oranges" 
//   vegetables: [ 'broccoli', 'zucchini', 'onions' ]
// }

$push

// { _id: 1, scores: [ 44, 78, 38, 80 ] } 
db.students.updateOne({ _id: 1 }, { $push: { scores: 89 } })
// { _id: 1, scores: [ 44, 78, 38, 80, 89 ] }    // 新增  89

$pullAll

// { _id: 1, scores: [ 0, 2, 5, 5, 1, 0 ] }
db.survey.updateOne( { _id: 1 }, { $pullAll: { scores: [ 0, 5 ] } } )
// { "_id" : 1, "scores" : [ 2, 1 ] } // 將 0,5 皆從陣列中移除了

陣列修飾符

修飾符可用之運算符格式
$each$push / $addToSet每一個
$position$push
$slice$push切片,正數n:保留前n個/負數n:保留後n個
$sort$push排序,1:小到大/-1:大到小

$each

// { _id: 2, item: "cable", tags: [ "electronics", "supplies" ] }
db.inventory.updateOne(
   { _id: 2 },
   { $addToSet: { tags: { $each: [ "camera", "electronics", "accessories" ] } } }
 )
// {
//   _id: 2,
//   item: "cable",
//   tags: [ "electronics", "supplies", "camera", "accessories" ]  // 原先已有 "electronics",僅 添加  "camera", "accessories"
// }

$position

// { "_id" : 2, "scores" : [  50,  60,  70,  100 ] } 
db.students.updateOne(
   { _id: 2 },
   {
     $push: {
        scores: {
           $each: [ 20, 30 ],
           $position: 2        // 陣列起點位置 開始為 0
        }
     }
   }
)
// { "_id" : 2, "scores" : [  50,  60,  20,  30,  70,  100 ] }

$slice

// { "_id" : 1, "scores" : [ 40, 50, 60 ] }
db.students.updateOne(
   { _id: 1 },
   {
     $push: {
       scores: {
         $each: [ 80, 78, 86 ],   // [ 40, 50, 60, 80, 78, 86 ]
         $slice: -5               // 後 5 個 [ 50, 60, 80, 78, 86 ]
       }
     }
   }
)
// { "_id" : 1, "scores" : [  50,  60,  80,  78,  86 ] }

// { "_id" : 2, "scores" : [ 89, 90 ] }
db.students.updateOne(
   { _id: 2 },
   {
     $push: {
       scores: {
         $each: [ 100, 20 ],  // [ 89, 90, 100, 20 ]
         $slice: 3            // 前 3 個 [ 89,  90,  100 ]
       }
     }
   }
)
// { "_id" : 2, "scores" : [  89,  90,  100 ] }

// {
//   "_id" : 3,
//   "quizzes" : [
//       { "wk": 1, "score" : 10 },
//       { "wk": 2, "score" : 8 },
//       { "wk": 3, "score" : 5 },
//       { "wk": 4, "score" : 6 }
//   ]
// }
db.students.updateOne(
   { _id: 3 },
   {
     $push: {
       quizzes: {
          $each: [ { wk: 5, score: 8 }, { wk: 6, score: 7 }, { wk: 7, score: 6 } ], // [{"wk":1,"score":10},{"wk":2,"score":8},{"wk":3,"score":5},{"wk":4,"score":6},{"wk":5,"score":8},{"wk":6,"score":7},{"wk":7,"score":6}]
          $sort: { score: -1 }, // score 大到小排列 [{"wk":1,"score":10},{"wk":2,"score":8},{"wk":5,"score":8},{"wk":6,"score":7},{"wk":4,"score":6},{"wk":7,"score":6},{"wk":3,"score":5}]
          $slice: 3 // 取前 3 個 [{"wk":1,"score":10},{"wk":2,"score":8},{"wk":5,"score":8}]
       }
     }
   }
)
// {
//   "_id" : 3,
//   "quizzes" : [
//      { "wk" : 1, "score" : 10 },
//      { "wk" : 2, "score" : 8 },
//      { "wk" : 5, "score" : 8 }
//   ]
// }

$sort

// {
//   "_id": 1,
//   "quizzes": [
//     { "id" : 1, "score" : 6 },
//     { "id" : 2, "score" : 9 }
//   ]
// }
db.students.updateOne(
   { _id: 1 },
   {
     $push: {
       quizzes: {
         $each: [ { id: 3, score: 8 }, { id: 4, score: 7 }, { id: 5, score: 6 } ], // [{"id":1,"score":6},{"id":2,"score":9},{"id":3,"score":8},{"id":4,"score":7},{"id":5,"score":6}]
         $sort: { score: 1 } // 小到大 [{"id":1,"score":6},{"id":5,"score":6},{"id":4,"score":7},{"id":3,"score":8},{"id":2,"score":9}]
       }
     }
   }
)
// {
//   "_id" : 1,
//   "quizzes" : [
//      { "id" : 1, "score" : 6 },
//      { "id" : 5, "score" : 6 },
//      { "id" : 4, "score" : 7 },
//      { "id" : 3, "score" : 8 },
//      { "id" : 2, "score" : 9 }
//   ]
// }

結論

撰寫前,有用一些圖文去細細的寫了一點,但資訊量真的太大了,朝翻譯官方文件著手,範例其實和官方文件範例相同,主要將註解翻譯成中文讓自己看得懂,官方文件其實講解得蠻清楚的,當然是為了往後讓自己翻找好用為主,用表格用程式碼註記回顧依然是我的習慣。

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