Firebase Firestore Part 2: Add Data/Query

จัดการข้อมูลบน Firestore

Tanabodin Kamol
iCreativeSystems
Published in
3 min readMar 2, 2020

--

บทความนี้จะมาต่อกันในส่วนของ การเพิ่มข้อมูลเข้าไปใน Firestore ในแบบที่ Realtime Database ทำไม่ได้ หากใครยังไม่เคยลองใช้ Firestore สามารถไปอ่านบทความก่อนหน้านี้ของผมได้ “ลองใช้งาน Firestore เบื้องต้น

Adding Data

- Set Document

การเพิ่มข้อมูลเข้าไปใน firestore จะทำได้โดยใช้ method set() โดยค่าที่เราจะเพิ่มเข้าไปใน document ได้ต้องเป็น dict object เท่านั้น

from google.cloud import firestore
data = {
u'name': 'Tanabodin Kamol',
u'age': 23
}
db.collection(u'users').document().set(data)
ถ้าไม่มีการใส่ชื่อของ document เข้าไป firestore จะมี auto-id ให้กับ document

โดยการใช้ method ถ้าเราใส่ชื่อของ document แล้วไม่มีชื่อนี้มาก่อน ข้อมูลก็จะถูกสร้างขึ้นมาให้ แต่ถ้ามีอยู่แล้วก็จะถูกเขียนทับ แต่แต่ถ้าเราต้องการให้ข้อมูลถูกรวมเข้าไปใน document ที่มีอยู่ เราสามารถให้ merge ทำได้

data = {
u'name': 'Tanabodin Kamol',
u'age': 23
}
db.collection(u'users').document(u'Bangkok').set(data, merge=True)

ถ้าไม่แน่ใจว่ามี document นั้นแล้วหรือเปล่า เราควรใส่ merge เข้าไปด้วยเพื่อป้องกันไม่ให้ข้อมูลของเราถูกเขียนทับ //ลองเขียนข้อมูลเพิ่มโดยที่ชื่อ document เดียวกันและไม่ใส่ merge ดู

เรายังสามารถนำ dict หรือ array เข้าไปใน document ได้อีกด้วย โดยเราสามารถดู data types ทั้งหมดที่ firestore support ได้ ที่นี่

ถ้าเราลองนำข้อมูลของ data type ทุกชนิดขึ้นไปบน firestore ซึ่งในที่นี้ผมจะนำข้อมูลชุดนี้ขึ้นไป

data = {
u'string_example': u'String to Firestore',
u'boolean_example': True,
u'number_example': 3.14159265,
u'date_example': datetime.now(),
u'array_example': [u'ICS', True, datetime(2017, 3, 9)],
u'null_example': None,
u'object_example': {
u'key_1': 'Python',
u'key_2': 'Drone',
u'key_3': {
u'name': 'Product',
u'quantity': 5,
},
}
}
db.collection(u'data').add(data)
เบื้องหลังของ method add() คือ document().set() ทำให้มีการ auto-id ให้

ผลลัพธ์ก็จะได้อย่างในภาพ แต่จะมีข้อจำกัดในการใช้งาน firestore อยู่ ยกตัวอย่างเช่น subcollections จะลึกสุดได้ 100 ชั้น, ขนาดสูงสุดของ document อยู่ที่ 1 MiB

- Update Document

หากเราต้องการที่จะเปลี่ยนค่าแค่บาง field โดยที่ไม่เขียนทับ document เดิม เราจะใช้ update()

data_ref = db.collection(u'data').document(u'5frEsKrVcpXFX3BO6RlN')

# Update the string field
data_ref.update({u'string_example': 'Update data with update()'})
ค่าของ string_example ถูกเปลี่ยนแปลงแล้ว ด้วย method update()

Update Object : เราสามารถเปลี่ยนค่าใน nested object ผ่าน update() ได้เหมือนกัน โดยเราจะอ้างถึงข้อมูลนั้นโดยใช้ “dot notation” แบบตัวอย่างข้างล่างนี้

data_ref = db.collection(u'data').document(u'5frEsKrVcpXFX3BO6RlN')

# Update the string field
data_ref.update({u'object_example.key_1': 'Robotics'})
ข้อมูลภายใน object ถูกเปลี่ยนแล้วด้วยการอ้างอิงแบบ dot notation

Update Array : เราสามารถจัดการข้อมูลใน array ได้ด้วยการใช้ ArrayUnion() หรือ ArrayRemove() โดย ArrayUnion() จะเป็นการเพิ่มข้อมูลเข้าไปใน array แต่จะเพิ่มค่าที่ยังไม่มีใน array เท่านั้น (Unique value) ส่วน ArrayRemove() จะเป็นการลบข้อมูลออกจาก array ของเรา

data_ref = db.collection(u'data').document(u'5frEsKrVcpXFX3BO6RlN')

# Atomically add a new data to the 'array_example' array field.
data_ref.update({u'array_example': firestore.ArrayUnion([u'TEST'])})

# Atomically remove a data from the 'array_example' array field.
data_ref.update({u'array_example': firestore.ArrayRemove([u'ICS'])})

Update Number : ถ้าเราต้องการเพิ่มค่าหรือลดค่าของ field ที่เป็น number เราสามารถใช้ Increment() ในการเพิ่ม/ลดค่าของ filed นั้น แต่ถ้าไม่มี field นั้นอยู่หรือ field นั้นไม่ใช่ number firestore จะทำการ set ค่าเป็นค่าที่เรากำหนด

data_ref = db.collection(u'data').document(u'5frEsKrVcpXFX3BO6RlN')data_ref.update({"population": firestore.Increment(50)})
data_ref.update({"population": firestore.Increment(-50)})
ผมไม่มี field `population` ทำให้ firestore ทำการ set ค่าของ field นี้ขึ้นมาให้

ข้อจำกัด ของการใช้ update() คือ เราสามารถ update document ได้เพียงครั้งเดียวต่อวินาที

Query Data

ในบทความก่อนหน้านี้ผมได้ให้ดึงข้อมูลจากทั้ง collection ออกมาโดยไม่ได้ใส่เงื่อนไขกำกับไว้เลย แต่ครั้งนี้จะเพิ่มขึ้นนิดหน่อย

ผมไปเพิ่มข้อมูลใน firestore ไว้แล้ว โดยมีแค่ field age กับ name

Query operation : เราจะทำการใส่เงื่อนไขในการ query collection กัน โดยเราจะใช้ method where() ซึ่งจะรับ parameters 3 ตัว เป็น <field_indexs_name>, <comparison>, <value> ตัว comparison หรือเงื่อนไขที่รองรับใน firestore มีทั้ง <, <=, ==, >, >=, array-contains, in, array-contain-any วิธีใช้งานก็จะเป็นตามตัวอย่างข้างล่างนี้

# Create a reference to the users collection
users_ref = db.collection(u'users')
# Create a query against the collection
query_ref = users_ref.where(u'age', u'<=', 20)
docs = query_ref.stream()

for doc in docs:
print(u'{} => {}'.format(doc.id, doc.to_dict()))

array-contains จะ return ทุก document ที่ field_indexs มี value ที่เราใช้ในการค้นหา

in และ array-contains-any จะมีการใช้งานคล้ายกันกับ array-contains แต่สามารถที่จะเปรียบเทียบพร้อมกันได้ถึง 10 value โดยการใช้งานจะเป็นอย่างในตัวอย่างข้างล่างนี้

users_ref = db.collection(u'users')

query = users_ref.where(
u'subject', u'array_contains_any', [u'math', u'physics']
)
return query

ข้อจำกัด

  • in กับ array-contains-any สามารถเทียบได้สูงสุด 10 value
  • เราสามารถใช้งานเงื่อนไข in หรือ array-contains-any ได้เพียงแค่ 1 ครั้งต่อการ query
  • เราสามารถที่จะใช้ array-contains ร่วมกับ in ได้ แต่ใช้ร่วมกับ array-contains-any ไม่ได้

Complex query เราสามารถใช้ where() เพื่อระบุเงื่อนไขให้มากขึ้นได้ โดยการใช้ where() จะเป็นเหมือนการ AND เงื่อนไขเพิ่ม

query_ref = db.collection(u'users').where(u'age', u'>=', 18).where(u'age', u'<=', 22)docs = query_ref.stream()

for doc in docs:
print(u'{} => {}'.format(doc.id, doc.to_dict()))

การ query ข้างต้นก็เหมือนการให้เงื่อนไขว่า if age>=18 AND age<=22 ซึ่งก็ทำให้ข้อมูลที่เรา query มามีขนาดเล็กลงและทำงานได้ไวยิ่งขึ้น

และเมื่อเราสามารถ query firestore ได้แล้ว เราก็สามารถที่จะใช้งาน firestore ได้สะดวกมากยิ่งขึ้น แต่อย่างไรก็ตามก็ต้องลองนำไปใช้กันดู หากติดปัญหาหรือมีคำถามใด ๆ ก็สามารถทิ้งคำถามไว้ได้นะครับ

REFERENCE

  1. https://firebase.google.com/docs/firestore/manage-data/add-data
  2. https://firebase.google.com/docs/firestore/query-data/queries

--

--

Tanabodin Kamol
iCreativeSystems

I always self-study about electronic devices and computer programming, So, I will share what I have learned for all of you! Sometime It’s code for Python