CSV ย่อมาจาก Comma-Seperated Values เป็นรูปแบบการบันทึกข้อมูลชนิดหนึ่ง ที่โปรแกรมสเปรดชีตนิยมใช้เป็น exchange format ให้โปรแกรมอื่นสามารถนำข้อมูลจากชีตออกไปใช้ หรือส่งข้อมูลเข้ามาในชีต
ความยืดหยุ่นของสเปรดชีต ทำให้เกิดการนำไปช่วยทำงานหลากหลาย ขณะเดียวก็เกิดความคลุมเครือของสิ่งที่อยู่ในตาราง ยุคสมัยที่คนใช้งานยังไม่เห็นความสำคัญของข้อมูล มักจะใช้เพื่อเอาท์พุต เช่น พิมพ์ออกมาเป็นรายงาน หรือแบบฟอร์มต่าง ๆ เพราะความง่ายทำให้สามารถประดับประดา จัดรูปแบบสี สไตล์ ฟอร์แมต หรือเพิ่มเติมค่าอื่น ๆ ที่อยากได้ตามต้องการ
ปัจจุบันมีโปรแกรมเฉพาะด้านที่ใช้งานสะดวกกว่า เช่น ระบบบัญชี หรือ ใช้ Google Form ให้รับข้อมูลแล้วบันทึกเข้าชีตอัตโนมัติได้ การเริ่มต้นอินพุตข้อมูลโดยคีย์ข้อมูลเข้าตารางตรง ๆ จึงเป็นวิธีของผู้ไม่มีความรู้หรือที่ไม่มีทางเลือกอื่นจริง ๆ ยิ่งข้อมูลมีปริมาณมาก ยิ่งต้องใช้ความอุตสาหะอย่างยิ่งยวด แถมยังตรวจทานความถูกต้องยาก การนำไฟล์ CSV จากระบบอื่นมาโหลดเข้าเป็นข้อมูลตั้งต้น จึงเป็นวิถีของการใช้สเปรดชีตทุกวันนี้มากกว่า
ข้อมูล คือ ข้อเท็จจริง การเพิ่มสูตรคำนวณ คือ การปรุงแต่งจากมุมมองของคุณ เพื่อวัตถุประสงค์อะไรบางอย่าง
ยกตัวอย่าง ยอดขายของลูกค้าเป็นข้อเท็จจริง แต่การจัดเกรด A, B, C เป็นค่าปรุงแต่ง
เป็นที่น่าเสียดายผู้ใช้สเปรดชีตจำนวนมากไม่เข้าใจคุณค่าของความเป็นข้อมูล แยกไม่ออกระหว่างตารางที่เป็นข้อมูล (Data) กับตารางที่ใช้แสดงผล (Presentation) เมื่อได้ข้อมูลมาแล้วก็ตัดต่อแก้ไขที่ตารางนั้น จนข้อเท็จจริงผสมปนเปกับสิ่งที่ถูกแต่งเติม ทำให้ไม่สามารถมาสร้างมุมมองเพื่อนำเสนอผลลัพธ์ที่หลากหลายจากตารางข้อมูลเดียวกัน
ตราบใดที่ สเปรดชีต ยังเป็นเครื่องมืออเนกประสงค์ที่ช่วยให้เราสามารถสร้างแบบจำลอง หรือประมวลผลข้อมูลได้สะดวกรวดเร็วสำหรับเรา เมื่อนั้นข้อมูลที่เป็น CSV ก็ช่องทางสำคัญในนำข้อมูลมาใช้ในการประมวลผล
มีข้อจำกัดของ CSV บางจุดที่ทำให้ไม่สามารถรองรับโมเดลข้อมูลสมัยใหม่ได้ โดยเฉพาะ JSON ทำให้กรณีนี้ไม่สามารถใช้เป็น exchange format ได้ ผมจึงเสนอแนวทางการขยายนิยามของ CSV ออกมาเป็น Hybrid CSV เพื่อให้สามารถแปลงข้อมูลระหว่างกันโดยไม่สูญเสียอัตลักษณ์
วัตถุประสงค์เบื้องต้นของผม ต้องการใช้งานกับ Document Database หรือ MongoDB ทั้งสองทิศทาง คือ ข้อมูลจากดาต้าเบสไปเข้าสเปรดชีต และ เอาข้อมูลจากสเปรดชีตไปเข้าดาต้าเบส
ข้อแตกต่างของ JSON อยู่ที่ข้อมูลไม่ได้แบบราบเป็น row/column สองมิติ เทียบเท่ากับตารางในชีต แต่สามารถมีข้อมูลในมิติย่อยได้อีก เรียกว่า object (ใน MongoDB เรียกว่า subdocument) เช่น ข้อมูลที่อยู่ ประกอบด้วย ถนน จังหวัด รหัสไปรษณีย์สามารถรวมอยู่ภายใน JSON object
ที่อยู่ address ประกอบด้วย {"street":"*", "province":"*", "zipcode":"*"} การเรียกชื่อข้อมูลสามารถใช้ address หมายถึงที่อยู่ทั้งหมด หรือ address.province หมายถึงข้อมูลจังหวัด ที่ประกอบอยู่ข้างใน address
ทำอย่างไรสามารถนำข้อมูลจากดาต้าเบสออกมาให้สเปรดชีต ใช้เพื่อสร้างรายงานหรือนำเสนอได้ กรณีนี้ไม่ยากนักเพราะสามารถอ้างถึงค่าย่อย ออกมาวางเรียงเป็นคอลัมน์ได้ และก็มีข้อจำกัดว่าอาจไม่สามารถโหลดออกมาใช้เพื่อซ่อมข้อมูลบางคอลัมน์แล้วส่งกลับไปเข้าดาต้าเบส
จะเห็นว่าอุปสรรคสำคัญ อยู่ที่ทำอย่างไรสามารถใช้สเปรดชีตออกแบบโมเดลข้อมูลแล้วนำไปโหลดเข้าดาต้าเบส เพราะความละเอียดของ CSV นั้นมีมิติข้อมูลได้แค่ 2 มิติ ขณะที่ JSON รองรับมิติได้มากกว่านั้น ถ้าจะกล่าวให้ชัดคือ ต้องหาทางทำให้ CSV เก็บข้อมูลหลายมิติได้
ในแง่ของข้อมูลที่เป็น JSON object หนทางที่เป็นได้มากที่สุด คือ การแปลง object นั้นให้อยู่ในรูปแบบของ text หรือ string ที่ CSV สามารถเก็บได้อยู่แล้ว ไม่ขัดกับมาตรฐานเดิม ทางฝั่ง JSON เองก็มีมาตรฐานแปลงข้อมูลจาก object ให้เป็น string อยู่ 2 ระดับ คือ JSON stringify (native format) และ YAML (human readable format) ดังนั้นการแปลงข้อมูล JSON object มากลายเป็น cell สามารถออกแบบให้ใช้ YAML standard ได้
JSON object → YAML (text) → CSV (cell)
แต่โปรแกรมสเปรดชีต ไม่รู้จัก JSON object หรือ YAML มองว่าเป็นข้อความธรรมดา ดังนั้นด้วยขีดความสามารถปัจจุบัน จึงไม่สามารถเข้าใจคุณสมบัติย่อยของ Object ที่อยู่ภายใน cell ได้ ไม่สามารถใช้สูตรคำนวณ (Formula) เพื่ออ้างอิงค่าคุณสมบัติย่อย มาใช้ภายในสูตรได้
SQL 2016 standard รองรับ JSON เริ่มจาก Oracle version 12c หลังจากนั้น PostgreSQL version 11 รวมทั้งดาต้าเบสอื่น ๆ ผมเชื่อว่าในอนาคตหากสเปรดชีตจะรองรับ JSON จึงมีโอกาสเป็นไปได้ (แต่ไม่รู้ว่าอีกนานแค่ไหน)
การพัฒนาโปรแกรมเพื่อใช้งานของผม แยกเป็น 2 ด้าน ส่งออก กับ นำเข้า เพื่อให้เข้าใจง่าย หากเป็นการเอาข้อมูลไปใช้ในสเปครดชีตแบบทางเดียว ไม่เอากลับมาเข้าดาต้าเบส แปลงข้อมูลนั้นให้อยู่ในรูปแบบของ native datatype ที่พร้อมใช้ตามปกติ เช่น เอาค่าของ address.province, address.zipcode มาวางเป็นคอลัมน์เหมือนกับเป็น CSV ธรรมดาได้เลย
แต่หากต้องการนำข้อมูลเข้าดาต้าเบส เรื่องนี้อาจซับซ้อนนิด จำเป็นต้องกำหนดข้อตกลงเป็น HCSV format ซึ่งขยายความหมายจาก CSV ดังนี้
การ mapping ชื่อหัวคอลัมน์ มาเป็นชื่อฟิลด์ในดาต้าเบส และเพิ่มสัญญลักษณ์ที่มีความหมายพิเศษ
1. ชื่อฟิลด์ที่ลงท้ายด้วย "$" หมายถึงค่าใน HCSV เป็น YAML จะต้องแปลงเป็น JSON Object ก่อนนำเข้า database เช่น "address$"
2. ชื่อฟิลด์ที่มี "." หมายถึงค่าของคุณสมบัติย่อย จะต้อง merger เข้ากับ Object ก่อนนำเข้า database เช่น "address.zipcode" จะต้องเอาค่า "zipcode" ไปรวมกับ Object "address"
ผลพลอยได้ของการตั้งชื่อฟิลด์เพื่อแปลง datatype JSON ดังกล่าว ทำให้สามารถแก้ปัญหาความสับสนของค่าตัวเลขใน CSV ด้วย เช่น เลขผู้เสียภาษี "0101001023001" ว่าจะต้องการเก็บข้อมูลเป็น string หรือ number ได้อีกด้วย ในแง่ดาต้าเบสมีผลแตกต่างเมื่อต้องการค้นหา หากเก็บค่าเป็น string สามารถค้นหาแบบ contains, starts with, ends with เช่น เลขผู้เสียภาษีที่ขึ้นต้นด้วย "0101" ขณะที่ค่าเป็น number จะค้นหาว่ามีค่ามากกว่าหรือน้อยกว่า
หากเราตั้งชื่อฟิลด์ว่า "taxid$" แล้วค่าในนั้นเป็นตัวเลขที่มี "..." ครอบ จะถูกแปลงเป็น string หากไม่มี "..." จะถูกแปลงเป็น number
ปัจจุบันยังไม่มี tools สำหรับแปลง HCSV เป็น JSON แนวทางที่ผมใช้อยู่ คือ เขียนขึ้นมาใช้เองด้วย JavaScript ใช้ lib อ่าน CSV มาเป็น JSON ก่อน หลังจากนั้นจึงเขียนโค้ดเพิ่มตรวจสอบชื่อฟิลด์ ที่เข้าเงื่อนไขข้างต้น แปลงข้อมูลอีกชั้นหนึ่ง โดยทำงานเป็น 2 ขั้นตอน ดังนี้
ตรวจสอบฟิลด์ที่ลงท้ายด้วย '$' ก่อน ใช้ lib YAML แปลงค่า แล้วเปลี่ยนชื่อฟิลด์เป็นชื่อที่ไม่มี '$'
ตรวจสอบฟิลด์ที่มี "." ใช้ lib YAML แปลงค่า แล้วเอาชื่อย่อย + ค่านั้นไปรวมกับฟิลด์แม่ที่มีอยู่แล้ว หากไม่มีฟิลด์แม่ก็เพิ่ม Object เปล่าของฟิลด์แม่ขึ้นมา
ตัวอย่างการใช้งานตัดต่อข้อมูลจากดาต้าเบสโดยใช้สเปรดชีตแล้วนำกลับเข้าไป สมมติว่าต้องการแก้ไขรหัสไปรษณีย์ ผมจะใช้วิธีเอาข้อมูลจากดาต้าเบสออกมาเป็น HCSV โดยมีฟิลด์สำคัญ "address$", "address.zipcode" เมื่อแก้ไขแล้วส่งกลับเข้า database ค่า "address.zipcode" จะถูก merge ไปรวมกับข้อมูลจาก "address$" ทำให้ได้ค่า zipcode ที่เป็นค่าใหม่
นอกจากนี้ยังใช้ HCSV เป็น alternative format สำหรับการ dump ข้อมูลจาก database เพื่อ backup โดย export ออกมาไว้ใน Excel และ Google Sheets ได้
สุดท้าย ผมเคยเล่าเรื่อง HCSV ที่เป็นไอเดียตั้งแต่สมัยแรก ๆ ที่เริ่มมีเคสใช้งานในโปรเจคท์ ซึ่งอาจมีประโยขน์โดยเฉพาะผู้ที่ใช้ MongoDB เป็นดาต้าเบส ได้แก่ การออกแบบ HCSV viewer และการออกแบบ CSV import ซึ่งอาจนำไปต่อยอดพัฒนาให้กลายเป็นเครื่องมือที่ใช้ได้ทั่วไปในอนาคต
- [MongoDB - CSV import](https://medium.com/@jsat66/mongodb-import-with-schema-less-csv-cb88d9c6971a)
- [Hybrid CSV and viewer](https://medium.com/@jsat66/hybrid-csv-และ-viewer-75fc61b839fe)
อ้างอิง
- [RFC 4180 - CSV format]( https://datatracker.ietf.org/doc/html/rfc4180)
- [SQL 2016 standard](https://modern-sql.com/blog/2017-06/whats-new-in-sql-2016)
- [PostgreSQL - datatype JSON](https://www.postgresql.org/docs/current/datatype-json.html)
- [Papaparse js - CSV parser](https://www.papaparse.com/)
[JS-YAML - YAML parser](https://github.com/nodeca/js-yaml#readme)
Komentar