Everything Jingle Bell แบบครอบจักวาล MongoDB [ตอนที่ 2.1: Array และเจาะลึกการ Update ข้อมูล]

ต่อจากตอนที่ 1 link ซึ่งในตอนที่ 2 นี้เราจะมาพูดถึงการทำงานของ MongoDB ซึ่งผมชอบที่สุดคือมันทำงานกับข้อมูลที่เป็น Array ได้ง่ายมาก ผมคิดว่านี้ก็เป็นจุดขายที่น่าสนใจอย่างนึงเลยครับ และนอกจากนี้ผมจะมาอธิบายคำสั่งต่างๆ ที่ไว้ทำการ Update ข้อมูลซึ่งทำให้การทำงานมีความยึดหยุ่นมากครับ เพราะเราสามารถสร้างเงือนไขที่ซับซ้อนได้ในการอัพเดทฐานข้อมูลของเรา เดียวผมจะแนะนำคำสั่งทั่งหมดก่อนตามนี้ครับ

Update Operators

คำสั่งที่ใช้งานกับ Fields

NameDescription
$incเพิ่มค่าของฟิลด์ value ที่เราระบุลงไป
$mulคูณค่าของฟิลด์ value ที่เราระบุลงไป
$renameเปลี่ยนชื่อฟิลด์
$setOnInsertให้เซตค่าลงถ้า update( ) นั่นเปลี่ยนทำงานแบบ insert( )  งง ละสิ?? เดียวผมอธิบายพร้อมตัวอย่างด้านล่าง
$setเซตค่าลงในฟิลด์เหมือน SQL นั่นแหละ
$unsetไว้ทำการลบฟิลด์นั่นออกไป
$minเอาไว้เปรียบเทียบค่าที่ใส่กับค่าที่มีอยู่ในฟิลด์ว่ามีค่าน้อยกว่าหรือป่าว ถ้าใช้ก็ใส่ค่าใหม่ไป
$maxเอาไว้เปรียบเทียบค่าที่ใส่กับค่าที่มีอยู่ในฟิลด์ว่ามีค่ามากกว่าหรือป่าว ถ้าใช้ก็ใส่ค่าใหม่ไป

ตัวอย่างการใช้งาน

ก่อนอื่นขอสร้างข้อมูล Mockup ก่อนแบบนี้ครับ ซึ่งผมจะใช้ข้อมูลนี้ในการอธิบายเซกชั่นนี้ครับ

 

$inc

ในตัวอย่างผมก็ได้ค้นหา product ที่มีค่า sku เท่ากับ abc123 และให้เซตค่า ด้วยคำสั่ง $inc โดยลบ quantity ออกไป 2 และ metrics.orders ให้บอกไปอีก 1 และนี้คือผลที่ได้

{ _id : 1, sku : abc123, quantity : 8, “metrics” : { orders : 3, ratings : 3.5 } }

 

$mul

อันนี้ก็จะเหมือนกันตัวอย่างบนเพียงแต่เปลี่ยนจากการบอกหรือลบเป็นการคูณแทน

{ _id: 1, sku: “abc123”, quantity: 20, metrics: { orders: 2, ratings: 3.5 } }

 

$rename

ตัวอย่างนี้ก็คือให้ค้นหา product ที่มี id เป็น 1 แล้วให้เปลี่ยนชื่อฟิลด์จาก quantity ไปเป็น quantitys ครับ

{ _id: 1, sku: “abc123”, quantitys: 10, metrics: { orders: 2, ratings: 3.5 } }

ตัวอย่างนี้ก็เป็นการทำงานข้อมูลด้วยการใช้ dot notation เข้าถึงตัวฟิลด์ที่เราต้องการ

{ _id: 1, sku: “abc123”, quantity: 10, metrics: { orders: 2, ratings: 3.5 } }

 

$setOnInsert

ตัวนี้ผมว่ามันเป็นคำสั่งที่น่าทึ่งอีกตัวนึงนะ เพราะคำสั่งตัวนี้จะเปลี่ยนให้คำสั่ง update() การเป็น insert() แล้วเซคค่าลงไปในระบบให้เลยครับ แต่มีข้อแม้ว่าการจะให้ update() มีความสามารถในการ insert() ได้นั่นจะต้องทำการเซต option ที่ชื่อว่า upsert:true สะก่อน เดียวเรามาดูวิธีการ update() ปกติกันก่อน

นี่คือเงือนไขการอัพเดทแบบปกติตัวแรกคือเงือนไขการค้นหา และอัพเดตอะไรตามลำดับ ปกติถ้าระบบไม่สามารถหาข้อมูลที่ตรงกับเงื่อนไขได้ก็จะไม่เกิดอะไรขึน แต่เราสามารถให้มันทำงานแบบนี้ได้คือ insert if not exist ให้เพิ่มค่าลงไปถ้าหาข้อมูลไม่เข้าเงือนไข แบบนี้ครับ

จากคำสั่งผมให้ระบบค้นหา sku ที่มีค่า abc123456 แต่แน่นอนว่าตัวอย่าง mockup ผมมีแค่ sku ที่มีค่า abc123 ดังนั่นระบบจะทำการไปเรียกคำสั่ง insert  มาทำงานแทน ผมก็จะได้ข้อมูลมาดังนี้ครับ

 

{ _id: 1, sku: “abc123”, quantity: 10, metrics: { order: 2, ratings: 3.5 } }

{ _id: ObjectId(“572b77b69eedcde34c89c906”) , sku: “abc123456”, quantity: 5, metrics: { order: 5, ratings: 5 } }

หมายเหตุ: _id ที่ได้นั่นระบบได้ทำการสร้างมาให้ตอนที่สร้างข้อมูลใหม่

ที่นี้เรามาลองใช้ $setOnInsert ดู

จากตัวอย่างนะครับ มีสองกรณีที่จะเกิดชึ้น

  • ถ้าระบบค้นหา _id: 3 เจอระบบจะทำการอัพเดต sku: “12345” และ  $setOnInsert ก็จะไม่ทำงาน
  • ถ้าระบบไม่เจอ _id: 3 ระบบจะไปเรียก insert() มาทำงานพร้อมกับเอาค่าใน $setOnInsert ไปเซตให้ข้อมูลชุดใหม่ และผลที่ได้คือ { “_id” : 3, “sku” : “12345”, “store” : “test”, “item” : “iphone” }

 

$set

ระบบจะไปค้นและทำการอัพเดตค่า quantity: 500 ให้นั่นเองครับ

{ _id: 1, sku: “abc123”, quantity: 500, metrics: { order: 2, ratings: 3.5 } }

ตัวอย่างนี้ก็คือการอัพเดตข้อมูลด้วย dot notation

{ _id: 1, sku: “abc123”, quantity: 500, metrics: { order: 2, ratings: 5 } }

 

$unset

อยากลบฟิลด์ไหนออกก็แค่ใส่ $unset แล้วใส่ค่าว่างให้มันลงไปมันก็จะหายไปทันทีครับแบบในตัวอย่าง

 

$min, $max

จากตัวอย่างตัวข้อมูล Mockup มี quantity: 10 แบบว่าถ้าเราใช้ { $min: { quantity: 5 } } ผลที่ได้คือ

{ _id: 1, sku: “abc123”, quantity: 5, metrics: { order: 2, ratings: 3.5 } } เพราะ 5 น้อยกว่า 10 นั่นเอง และถ้าเราใช้ { $min: { quantity: 500 } } ผลที่ได้ก็จะเป็น

{ _id: 1, sku: “abc123”, quantity: 500, metrics: { order: 2, ratings: 3.5 } } เพราะ 500 มากกว่า 10 ครับ

 

คำสั่งที่ใช้งานกับ Array

ต่อไปเราจะมาดูวิธีการทำงานกับข้อมูลที่เป็น Array ซึ่งง่ายมากเลยครับ และผมคิดว่ามันเป็นอะไรที่น่าทึ่งมากทีเดียว แต่จริงๆ มันไม่ค่อยน่าแปลกใจเท่าไรเพราะ MongoDB ใช้การเก็บข้อมูลแบบ JSON นั่นแปลว่าเราจะมีข้อมูลทั่ง Object และ Array อยู่ด้วยกัน แต่ที่มันทำให้เราง่ายขึ้นมาเพราะมันมีคำสั่งมาจัดการให้

$ใช้ในการระบุ index ของ array โดยที่เราไม่ต้องใส่ตัวเลขของ index ลงไป
$addToSetใส่ข้อมูลใส่ไปใน array ถ้าข้อมูลนั่นไม่ได้มีอยู่แล้ว (ห้ามข้อมูลซ่ำกัน)
$popลบข้อมูลตัวแรกหรือตัวสุดท้ายออก
$pullAllลบข้อมูลใน array ออกจะเป็นแบบ matching values
$pullลบข้อมูลใน array ออกที่ตรงกับเงือนไขการคิวรี่แบบ matching query
$pushAllคำสั่งนี้ยกเลิกแล้วให้ไปใช้งาน $push หรือ $each แทน
$pushเพิ่มข้อมูลลงไปใน array นั่นเอง (ข้อมูลซ้ำกันได้)

ก่อนอื่นทำ Mockup ไว้สำหรับอธิบายกันก่อนโดยผมจะใช้แบบนี้

Find Array item

ก่อนจะเริ่มการใช้คำสั่งต่างๆ เรามาดูวิธีการ find ข้อมูลที่เป็น Array เพราะในตอนที่ 1 ผมไม่ได้พูดไปซึ่งผมยกมาในนี้แทน การค้นหาข้อมูลที่เป็น array นั่นง่ายมาก ตอนแรกที่ผมใช้ก็ไม่คิดว่ามันจะง่ายแบบนี้เหมือนกัน แบบไหนมาดูกัน

ผลที่ได้คือ  { _id : 1 , sku :  abc123,  quantity :  10,  items :  [ “java”, “c”, “php” ],  prices : [Object, Object, Object ] } เราก็จะได้ข้อมูลที่มี items ที่มีค่า “c” อยู่ข้างในนั่นเอง เพราะระบบทำการวนลูปค้นหาให้เราไปแล้วครับ จากนั่นจึงเอาค่ากลับมาให้เรา

 

$

ตัวนี้อาจจะฟังดู งงๆ แต่มันเป็นคำสั่งของระบบที่ใช้แทนการใส่ index ของ array ซึ่งเมื่อแทนค่าลงไประบบก็จะทำการแทนที่ด้วยตัวเลขให้  แล้วระบบมันรู้ได้ไงว่าเราจะทำงาน index ไหน ?? มาดูตัวอย่างกัน

จากตัวอย่างผมสร้างเงือนไขการอัพเดตด้วยการหา _id  == 1 && items == “c” และเซตค่าให้กับ items เป็น “c#” การทำงานของระบบนั่น ผมได้อธิบายในส่วนของ find ไปแล้วว่าระบบจะไปวนลูปหามาให้ดังนั่นระบบจะเก็บ index ที่มันหาเจอไว้ให้เราด้วย ซึ่งถ้าดูจากตัวอย่าง “c” จะอยู่ลำดับที่ 1 และเมื่อเราใช้ $ ลงไป เราอาจะเขียนแทนด้วยโค้ดให้เข้าใจได้ว่า “items[1] = c#” หรือ   “items.1 = c#” นั่นเองครับ

หมาเหตุ: $ ใช้ได้กับ index ตัวแรกที่ระบบค้นหาเจอตามเงือนไข นั่นหมายความว่าถ้าเรามี  items: [“java”, “c”, “php”, “c”] แปลว่าระบบจะอัพเดตแค่ “c” ที่อยู่ระหว่าง “java” และ “php” นั่นเอง ถ้าต้องการให้มันอัพเดตทุกตัวละ? ให้ไปใช้ $each ที่เป็นวนลูป เดียวเราจะสอนในส่วนต่อไป

ลองมาดูอีกแบบนึง ถ้าระบบเราเก็บ array ไว้ใน Object ละแบบนี้

ผลที่เราได้ก็จะคล้ายๆ กับข้างบนเพียงแต่ว่าผมทำงานกับข้อมูลที่เป็น array ซึ่งเก็บเอา Data Object เอาไว้ครับ และเราก็แทนค่า index ด้วยเครื่องหมาย $ นั่นเอง ครับ

 

$addToSet

เป็นการใส่ค่าลงไปใน array อย่างนึงครับ แต่มีข้อแม้ว่าข้อมูบต้องไม่ซ้ำกับข้อมูลที่มีก่อนหน้านี้ และฟิลด์นั่นต้องมี type เป็น array 

ผลที่ได้ก็จะเป็น { _id : 1 , sku : abc123, quantity : 10, items : [ “java”, “c”, “php”, [“python”,  ada”] ], prices : [Object, Object, Object ] } ใันก็จะมี array เพิ่มไปใน array เพราะเราสั่ง $addToSet เข้าไปนั่นเองครับ

ผลทีได้ก็จะเป็น { _id : 1 , sku : abc123, quantity : 10, items : [ “java”, “c”, “php”, “python” ], prices : [Object, Object, Object ] } ก็จะมี “python” เข้าไปต่อท้ายครับ

ผลทีได้ก็จะเป็น { _id : 1 , sku : abc123, quantity : 10, items : [ “java”, “c”, “php” ], prices : [Object, Object, Object ] } จะไม่มีอะไรเพิ่มเข้าไปเพราะข้อมูลไปซ่ำกับของที่มีอยู่แล้ว

 

$pop

ลบข้อมูลตัวแรกของ array

ข้อมูลตัวแรกก็จะถูกลบออกแบบนี้ครับ { _id : 1 , sku : abc123, quantity : 10, items : [ “c”, “php” ], prices : [Object, Object, Object ] } เพราะเราใส่ค่า -1 แปลว่าให้ลบข้อมูลตัวแรกสุดออกไป

ข้อมูลตัวแรกก็จะถูกลบออกแบบนี้ครับ { _id : 1 , sku : abc123, quantity : 10, items : [“java”, “c” ], prices : [Object, Object, Object ] } เพราะเราใส่ค่า 1 แปลว่าให้ลบข้อมูลตัวสุดท้ายออกไป

 

$pullAll

ตัวคำสั่งตัวนี้จะไว้ทำการลบค่าออกจาก array ซึ่งจะเอาลบค่าที่ตรงกับ parameter ที่เราส่งเข้ามา จากนั่นจะระบบจะทำการลบค่าที่ตรงกันออกจาก array ให้เราครับ และเราจะใช้ Mockup data แบบนี้แทน

{ _id: 1, items: [0,  1,  2,  5,  8,  0, 2, 4] }

ที่ลองมาดูตัวอย่างครับ

ผลที่ได้คือค่าที่ตรงกับเงือนไขจะถูกตัดออกไปทันที

{ _id: 1, items: [1,  8,  4] }

 

$pull

ตัวอย่างรูปแบบการใช้งาน

{ $pull: { <field1>: <value|condition>, <field2>: <value|condition>, … } }

คำสั่งตัวนี้นอกจากจะใส่ parameter ที่เป็นค่าใน array ที่ต้องการลบแล้วยังสามารถสร้างเงือนไขได้อีกด้วย แต่มีกฏอยู่ว่า

ถ้าใส่มาเป็น condition แล้วตัวฟิลด์นั่นเป็น array ที่เก็บ Object ไว้ระบบจะทำการรันคำสั่งลงไปในทุกๆ ตัวของ Object

ตัวอย่าง Document ที่เก็บ Object ไว้

{
_id: 1,
 results: [
              { item: “A”, score: 5 },
              { item: “B”, score: 8, comment: “Strongly agree” }
       ]
}

 ถ้าใส่มาเป็น value เพื่อทำการลบค่าใน array ระบบจะทำการลบค่าที่อยู่ใน array ที่ตรงกับ parameter ที่ใส่มาเท่านั่น หรือการทำ match value (เหมือน $pullAll นั่นเอง)

ถ้าใส่มาเป็น value เพื่อทำการลบ row นั่นๆ ระบบจะตรวจว่า parameter ที่ใส่ และชื่อฟิลด์ต้องตรงกันเท่านั่น row นั่นจึงจะถูกลบ หรือการทำ match value และ match field

ตัวอย่างการลบข้อมูลใน array ที่เท่ากับ (การทำงานแบบ Equal value) parameter

ผลที่ได้คือ

{ _id: 1, items: [ “laptop”, “mobile”, “tablet” ] } ซึ่งก็จะเหมือนกับการใช้ $pullAll ครับถ้าค่าตรงกันก็ลบออกไป

 

ตัวอย่างการลบข้อมูลใน Array ที่ตรงกับเงื่อนไขที่ระบุ (การทำงานแบบ Match conditions)

ผลที่ได้คือ

{ _id: 1, votes: [ 3, 5 ] } ถ้ามีข้อมูลในไหน array ที่ตรงกับเงื่อนไขระบบก็จะลบออกไปทันที

 

ตัวอย่างการลบข้อมูลแบบที่ array นั่นเก็บ Object ไว้ (กาทำงานแบบ match value และ match field)

ผลที่ได้จาการคำสั่งก็จะได้ว่า

{
“_id” : 1,
“results” : [ { “item” : “A”, “score” : 5 } ]
},
{
“_id” : 2,
“results” : [
{ “item” : “C”, “score” : 8, “comment” : “Strongly agree” },
{ “item” : “B”, “score” : 4 }
]
}

การทำงานของมันก็อธิบายง่ายๆ แบบนี้ว่าจากเงื่อนไขที่เราระบุมา ระบบจะทำการวนลูปเข้าไปหาในแต่ละ index ในทุกๆรอบระบบก็จะไปว่ามี index ไหนที่มีค่าตรงกับเงื่อนไขบาง แบบตัวอย่างคือ find result where score == 8 && item == “B” เขียนให้ดูเป็นภาษาโค้ดน่าจะพอเข้าใจมาขึ้นนะครับ

จากเงื่อนไขข้างบน เรายังสามารถที่จะเขียนได้อีกแบบซึ่งผมขอแนะนำอีกคำสั่ง $elemMatch และเรายังสามารถที่ะเขียนให้ได้ผลออกแบบด้านบนด้วยการใช้  $elemMatch  เป็นการทำงานแบบ match value และ match field ดังนั่นผลที่ได้จึงออกมาเหมือนกันแบบตัวอย่าง

 

$push

เป็นคำสั่งที่ไว้ใสข้อมูลลงไปใน array เท่านั่งเองครับ

และนี่คือผลลัพธ์ครับ { _id: 1, votes: [ 3, 5, 6, 7, 7, 8, 89 ] }

 

บทความนี้ขอจบเท่านี้ก่อนครับ ไว้บทความหน้า ตอนที่ 2.2: Array และเจาะลึกการ Update ข้อมูล กับตอนที่เราจะมาใช้คำสั่ง Modifiers ที่ใช้งานกับ Array บทความนี้ผมขอจบก่อนเพราะมันเยอะมากๆ ครับ

Facebook Comments