Slide 1

Slide 1 text

Cookpad Inc. Firestore ͷΫΤϦͱશจݕࡧ ࡾӜ࿨໵

Slide 2

Slide 2 text

Cookpad Inc. All Rights Reserved. ࣗݾ঺հ w໊લࡾӜ࿨໵ wܦྺ wCookpad 17৽ଔ (Komerco ࣄۀ෦ wiOSྺ໿5೥ Firebase ྺ1೥ͪΐͬͱ wTwitter: __miup (ΞϯμʔείΞ2ຊʂ wGithub: miuP

Slide 3

Slide 3 text

Cookpad Inc. All Rights Reserved. ࠓ೔࿩͢͜ͱ wFirestore ͷΫΤϦͰͰ͖Δ͜ͱ wFirestore ͷΫΤϦͰͰ͖ͳ͍͜ͱ wղܾࡦ

Slide 4

Slide 4 text

Cookpad Inc. All Rights Reserved. Firestore ͷΫΤϦͰͰ͖Δ͜ͱ wsort worderBy wwhere wisEqualTo wisLessThan (orEqualTo) wisGreaterThan (orEqualTo)

Slide 5

Slide 5 text

Cookpad Inc. All Rights Reserved. Firestore ͷΫΤϦͰͰ͖Δ͜ͱ wpaging wlimit wstartAfter, endBefore (order ͍ͯ͠Δ஋, DocumentReference) wetc…

Slide 6

Slide 6 text

Cookpad Inc. All Rights Reserved. Firestore ͷΫΤϦͰͰ͖Δ͜ͱ 1ճͷΫΤϦͰ isLessThan ͱ isGreaterThan ͸ 1ͭͷ Field ʹର͔ͯ͠͠࢖͑ͳ͍ʂ ͨͩ͠ʂ
 ੍໿͕͋Δ

Slide 7

Slide 7 text

interface Product { name: string // ঎඼໊ price: number // Ձ֨ stock: number // ࡏݿ isActive: boolean // ࿦ཧ࡟আ createdAt: firestore.Timestamp updatedAt: firestore.Timestamp }

Slide 8

Slide 8 text

Cookpad Inc. All Rights Reserved. Firestore ͷΫΤϦͰͰ͖Δ͜ͱ w୯ҰͷϑΟʔϧυʹର͢Δෳ਺ͷൣғൺֱ wෳ਺ͷϑΟʔϧυʹର͢Δ౳Ձԋࢉࢠ wެ։தͷ5000ԁ~10000ԁͷࡏݿͷlͳ͍z঎඼Λऔಘ

Slide 9

Slide 9 text

const products = await admin.firestore().collection('products') .where('isActive', '==', true) .where(‘stock', '==', 0) .where('price', '<=', 10000) .where('price', ‘>=', 5000) .then(querySnapshot => { return querySnapshot.docs.map(doc => { ... }) })

Slide 10

Slide 10 text

Cookpad Inc. All Rights Reserved. Firestore ͷΫΤϦͰͰ͖Δ͜ͱ wෳ਺ͷϑΟʔϧυʹ·͕ͨΔΫΤϦ wΧελϜΠϯσοΫε͕ඞཁ ෳ߹ΠϯσοΫεΈ͍ͨͳ΋ͷʣ wΫΤϦ౤͛ͯΤϥʔ͕ฦͬͯ͘Δͱ URL ͕ॻ͍ͯ͋ΔͷͰͦ͜ Λ౿Ί͹؆୯ʹઃఆͰ͖Δ

Slide 11

Slide 11 text

Cookpad Inc. All Rights Reserved. Firestore ͷΫΤϦͰͰ͖ͳ͍͜ͱ wશจݕࡧ -*,&΋ wisNotEqualTo (݁ߏͭΒ͍) wෳ਺ͷϑΟʔϧυʹର͢Δൣғൺֱ wެ։தͷ5000ԁ~10000ԁͷࡏݿͷl͋Δz঎඼Λऔಘ

Slide 12

Slide 12 text

const products = await admin.firestore().collection('products') .where('isActive', '==', true) .where('stock', '>', 0) .where('price', '<=', 10000) .where('price', ‘>=', 5000) .then(querySnapshot => { return querySnapshot.docs.map(doc => { ... }) }) ❌

Slide 13

Slide 13 text

const products = await admin.firestore().collection('products') .where('isActive', '==', true) .where('stock', '!=', 0) .where('price', '<=', 10000) .where('price', ‘>=', 5000) .then(querySnapshot => { return querySnapshot.docs.map(doc => { ... }) }) ❌

Slide 14

Slide 14 text

Cookpad Inc. All Rights Reserved. Firestore ͷΫΤϦͰͰ͖ͳ͍͜ͱ wެ։தͷ5000ԁ~10000ԁͷࡏݿͷl͋Δz঎඼Λऔಘ͕Ͱ͖ͳ͍ wશจݕࡧ͕Ͱ͖ͳ͍ ݁ߏݫ͍͠

Slide 15

Slide 15 text

Cookpad Inc. All Rights Reserved. Ͳ͏͢Ε͹ʜ

Slide 16

Slide 16 text

Cookpad Inc. All Rights Reserved. Algolia 4BB4ʹཔΖ͏ શจݕࡧʢincremental search) Λఏڙ͍ͯ͠Δ SaaS iOS, Android, Web Ͱ SDK ఏڙ͞Ε͍ͯΔ ʢଞʹ΋ݕࡧ4BB4͋Δ͚Ͳެࣜʹ΋໊લ͕ग़͍ͯΔͷͰ"MHPMJBΛ঺հ͠·͢ʣ

Slide 17

Slide 17 text

Cookpad Inc. All Rights Reserved. ྲྀΕ Cloud Firestore Cloud Functions Algolia Save Document Event trigger Algolia API Search

Slide 18

Slide 18 text

algoliasearch(functions.config().algolia.app_id, functions.config().algolia.api_key) const productsIndex = algolia.default.initIndex('products') functions.firestore.document('products/{productID}').onCreate(async (snapshot, context) => { const firProduct = new Tart.Snapshot(snapshot) // ࡟আࡁΈͷ঎඼͸ొ࿥͠ͳ͍ if (!firProduct.data.isActive) { return undefined } // Algolia ʹอଘ͢Δσʔλʹม׵(Reference Λ ID ʹ͢Δͱ͔͢Δ) const product = new Product(firProduct) return new Promise((resolve, reject) => { productsIndex.addObject(product, async (error, response) => { if (error) { throw error } else { resolve(response) } }) }) })

Slide 19

Slide 19 text

Cookpad Inc. All Rights Reserved. ྲྀΕ Cloud Firestore Cloud Functions Algolia Save Document Event trigger Algolia API Search

Slide 20

Slide 20 text

Cookpad Inc. All Rights Reserved. ܕ͕ͳ͍ Algolia ݕࡧ݁Ռʹܕ͕ͳ͍
 Swift Ͱॻ͘ͳΒܕ͕ཉ͍͠
 Kotlin Ͱ΋ Java Ͱ΋ TypeScript Ͱ΋ಉ͚ͩ͡Ͳ

Slide 21

Slide 21 text

Cookpad Inc. All Rights Reserved. ϥΠϒϥϦ࡞ͬͨ

Slide 22

Slide 22 text

Cookpad Inc. All Rights Reserved. Algent Type Safe Algolia Search Client for Swift
 https://github.com/miuP/Algent

Slide 23

Slide 23 text

Cookpad Inc. All Rights Reserved. ࢖͍ํ wσʔλͷܕΛ࡞Δ wRequest Λ࡞Δ w౤͛Δ

Slide 24

Slide 24 text

struct User: Decodable { let objectID: String let name: String let bio: String let isActive: Bool let followerCount: Int let followeeCount: Int let _tags: [String] }

Slide 25

Slide 25 text

struct SarchUserRequest: AlgoliaRequestProtocol { // set search result type typealias HitType = User let page: Int let per: Int let text: String? let hashtags: [String]? var indexName: String { return "user" } var query: AlgentQuery { let query = AlgentQuery(query: text) query.page = UInt(page) query.hitsPerPage = UInt(per) if let hashtags = hashtags { query.tagFilters = hashtags } return query } init(page: Int, per: Int, text: String? = nil, hashtags: [String]? = nil) { self.page = page self.per = per self.text = text self.hashtags = hashtags } }

Slide 26

Slide 26 text

let request = SarchUserRequest(page: 0, per: 20, text: "", hashtags: []) Algent.shared.search(request: request) { result in switch result { case .success(let response): // response is AlgoliaResponse print(response.hits) // see hit object:[HitType] case .failure( let error): print(error) } }

Slide 27

Slide 27 text

Cookpad Inc. All Rights Reserved. ·ͱΊ wFirestore ͰͷΫΤϦ wൣғࢦఆΛҟͳΔFieldʹ͔͚ΒΕͳ͍ wisNotEqualTo ͕ͳ͍ wLIKEͱ͔શจݕࡧ͕Ͱ͖ͳ͍ wAlgolia w֎෦αʔϏεʹͳΔͷͰ࿈ܞ͕ඞཁ(Firebase ͷ༗ྉϓϥϯඞཁ) wAlgent ࢖ͬͯΈ͍ͯͩ͘͞