ความแตกต่างระหว่าง set กับ {merge: true} และ update


121

ในCloud Firestoreมีการดำเนินการเขียนสามแบบ:

1) เพิ่ม

2) ชุด

3) อัปเดต

ในเอกสารระบุว่าการใช้set(object, {merge: true})จะผสานวัตถุกับวัตถุที่มีอยู่

สิ่งเดียวกันเกิดขึ้นเมื่อคุณใช้update(object) ดังนั้นความแตกต่างคืออะไรถ้ามี? ดูเหมือนแปลกที่ google จะซ้ำกันตรรกะ

คำตอบ:


272

วิธีที่ฉันเข้าใจความแตกต่าง:

  • setโดยmergeจะไม่เขียนทับเอกสารหรือสร้างขึ้นหากยังไม่มี

  • setด้วยmergeจะอัปเดตฟิลด์ในเอกสารหรือสร้างขึ้นหากไม่มีอยู่

  • update จะอัปเดตฟิลด์ แต่จะล้มเหลวหากไม่มีเอกสาร

  • create จะสร้างเอกสาร แต่ล้มเหลวหากมีเอกสารอยู่แล้ว

นอกจากนี้ยังมีความแตกต่างในชนิดของข้อมูลที่คุณให้ไปและsetupdate

สำหรับsetคุณมักจะมีที่จะให้ข้อมูลเอกสารที่มีรูปทรง:

set(
  {a: {b: {c: true}}},
  {merge: true}
)

ด้วยupdateคุณยังสามารถใช้เส้นทางข้อมูลสำหรับการปรับปรุงค่าซ้อนกัน:

update({
  'a.b.c': true
})

1
แต่คุณพบcreateวิธีการใน API ที่ไหน
ZuzEL

2
cloud.google.com/nodejs/docs/reference/firestore/0.8.x/…สำหรับ node.js. ดูเหมือนว่า Web API จะไม่มีวิธีการดังกล่าว ไม่แน่ใจว่าคุณอยู่บนแพลตฟอร์มใด :)
Scarygami

11
ความแตกต่างอีกประการหนึ่งที่คุณสามารถพูดถึงคือsetการทำงานบนข้อมูลที่เป็นรูปเอกสารซึ่งupdateใช้เส้นทางของฟิลด์และคู่ค่า ซึ่งหมายความว่าคุณสามารถเปลี่ยนแปลงค่าที่ซ้อนกันอย่างลึกซึ้งโดยupdateที่ยุ่งยากsetกว่าได้ ตัวอย่างเช่น: VSset({a: {b: {c: true}}}, {merge: true}) update('a.b.c', true)
Gil Gilbert

ถ้าฉันต้องการอัปเดตค่าในเอกสารมันสมเหตุสมผลแล้วที่ฉันต้องการอัปเดตเอกสารที่มีอยู่แล้วดังนั้นฉันคิดว่า set + mergeall นั้นไม่เป็นประโยชน์เพราะมันจะสร้างมันขึ้นมาโดยที่ไม่มีเอกสารอยู่
John Balvin Arias

หากข้อมูลที่คุณระบุให้กับคำสั่ง set มีฟิลด์ที่เป็นโมฆะจะตั้งค่าฟิลด์เป็น null หรือไม่หากมีอยู่แล้วในฐานข้อมูลหรือจะปล่อยไว้เฉยๆ
user1023110

72

ความแตกต่างอีกประการหนึ่ง (ขยายคำตอบของ Scarygami) ระหว่าง "set with merge" และ "update" คือเมื่อทำงานกับค่าที่ซ้อนกัน

หากคุณมีเอกสารที่มีโครงสร้างดังนี้:

 {
   "friends": {
     "friend-uid-1": true,
     "friend-uid-2": true,
   }
 }

และต้องการเพิ่ม {"friend-uid-3" : true}

ใช้สิ่งนี้:

db.collection('users').doc('random-id').set({ "friends": { "friend-uid-3": true } },{merge:true})

จะส่งผลให้ข้อมูลนี้:

 {
   "friends": {
     "friend-uid-1": true,
     "friend-uid-2": true,
     "friend-uid-3": true
   }
 }

อย่างไรก็ตามการupdateใช้สิ่งนี้:

db.collection('users').doc('random-id').update({ "friends": { "friend-uid-3": true } })

จะส่งผลให้ข้อมูลนี้:

 `{
   "friends": {
     "friend-uid-3": true
   }
 }`

1
คุณลองทดสอบด้วยตัวเองแล้วหรือยัง? มีส่วนหนึ่งในเอกสารประกอบ: "หากต้องการอัปเดตบางฟิลด์ของเอกสารโดยไม่เขียนทับทั้งเอกสารให้ใช้ลิงก์
Finlay Percy

2
ฉันคิดออกแล้ว ฉันเคยลองสิ่งนี้กับอาร์เรย์มาก่อนเท่านั้น ที่ฉันต้องการเพิ่มวัตถุลงในอาร์เรย์และทุกอย่างถูกเขียนทับสำหรับอาร์เรย์นั้น มันไม่ทำงานกับเขตข้อมูลที่มีอาร์เรย์ ... มันยืนเป็นเอกสาร
ravo10

1
เพิ่งได้ข้อสรุปเดียวกันหลังการทดสอบ ฉันหวังว่าพวกเขาจะเพิ่มตัวเลือกที่มีผลเช่นเดียว{ merge: true }กับฟังก์ชันอัพเดต
Johnride

1
ขอบคุณสำหรับคำตอบนี้! แม้ว่าตัวอย่างจะดูเรียบง่าย แต่ก็ทำให้มันดูสะอาดตากว่าคำตอบที่ยอมรับว่าข้อใดดีกว่าสำหรับกรณีการใช้งานของฉัน
naiveai

2
เพื่อหลีกเลี่ยงการเขียนทับข้อมูลในสาขาที่ซ้อนกัน (ในขณะที่คำตอบข้างต้น) เมื่อใช้updateคุณสามารถใช้จุดสัญกรณ์ พฤติกรรมการเขียนทับupdateจะแตกต่างกันหากคุณไม่ใช้ / ไม่ใช้สัญกรณ์จุด
Tedskovsky

8

ตามเอกสาร: https://firebase.google.com/docs/firestore/manage-data/add-data#update_fields_in_nested_objects

สัญลักษณ์จุดช่วยให้คุณสามารถอัปเดตเขตข้อมูลที่ซ้อนกันเดียวโดยไม่ต้องเขียนทับเขตข้อมูลที่ซ้อนกันอื่น ๆ หากคุณอัปเดตเขตข้อมูลที่ซ้อนกันโดยไม่มีสัญลักษณ์จุดคุณจะเขียนทับฟิลด์แผนที่ทั้งหมด

ตามที่ระบุไว้ข้างต้นสิ่งนี้จะแทนที่โครงสร้างเพื่อนทั้งหมด

db.collection('users').doc('random-id').update({
    "friends": {
        "friend-uid-3": true
    }
})

สิ่งนี้ไม่ได้

db.collection('users').doc('random-id').update({
    "friends.friend-uid-3": true
})
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.