Firebase Firestore Part 2: Add Data/Query
จัดการข้อมูลบน Firestore
บทความนี้จะมาต่อกันในส่วนของ การเพิ่มข้อมูลเข้าไปใน 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)
โดยการใช้ 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)
ผลลัพธ์ก็จะได้อย่างในภาพ แต่จะมีข้อจำกัดในการใช้งาน 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()'})
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'})
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)})
ข้อจำกัด ของการใช้ update()
คือ เราสามารถ update document ได้เพียงครั้งเดียวต่อวินาที
Query Data
ในบทความก่อนหน้านี้ผมได้ให้ดึงข้อมูลจากทั้ง collection ออกมาโดยไม่ได้ใส่เงื่อนไขกำกับไว้เลย แต่ครั้งนี้จะเพิ่มขึ้นนิดหน่อย
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 ได้สะดวกมากยิ่งขึ้น แต่อย่างไรก็ตามก็ต้องลองนำไปใช้กันดู หากติดปัญหาหรือมีคำถามใด ๆ ก็สามารถทิ้งคำถามไว้ได้นะครับ