iOS
...
Data Objects
ParseSwiftでiOSアプリのリレーショナルデータクエリを理解する
12 分
リレーショナルクエリ イントロダクション 前の ガイド https //www back4app com/docs/ios/parse swift sdk/data objects/query cookbook では、back4appデータベースでさまざまなクエリを実行する方法について詳しく説明しました。このガイドでは、リレーションを持つオブジェクトに関する特定のタイプのクエリに焦点を当てます。 前提条件 このチュートリアルを完了するには、次のものが必要です: back4appで 作成されたアプリ クエリをテストするための基本的なiosアプリ 目標 back4appデータベースに保存されたリレーショナルデータを parseswift sdk parseswift sdk を使用してクエリします。 1 query\<u>クラスについての簡単なレビュー back4appデータベースで実行されるクエリは、一般的なクラス query\<u> query\<u> を介して行われます。一般的なパラメータ u u ( parseobject parseobject プロトコルに準拠) は、データベースから取得しようとしているオブジェクトのデータ型です。 例えば myobject myobject のようなデータ型がある場合、次の方法でback4appデータベースからこれらのオブジェクトを取得します。 1 import parseswift 2 3 struct myobject parseobject { 4 5 } 6 7 let query = myobject query() 8 9 // executes the query asynchronously 10 query find { result in 11 // handle the result (of type result<\[myobject], parseerror>) 12 } 公式ドキュメントの query\<u> query\<u> クラスについては、 こちらの公式ドキュメントで https //github com/parse community/parse swift お読みいただけます。 2 back4appデータベースにデータを保存する クエリを実行する前に、back4appデータベースにいくつかのデータを設定する必要があります。私たちは5種類のオブジェクトを保存します author 1 struct author parseobject { 2 3 var name string? 4 } book 1 struct book parseobject { 2 3 var title string? 4 var publisher publisher? 5 var publishingdate date? 6 } isbd 1 struct isbd parseobject { 2 3 var isbn string? 4 var book pointer\<book>? 5 } publisher 1 struct publisher parseobject { 2 3 var name string? 4 } bookstore 1 struct bookstore parseobject { 2 3 var name string? 4 } さらに、リレーショナルデータのクエリを構築するために、次の関係を実装します 1 1 の関係 書籍 書籍 と isbd isbd 1\ n の関係 書籍 書籍 と 出版社 出版社 m\ n の関係 書籍 書籍 と 著者 著者 m\ n の関係 書店 書店 と 書籍 書籍 私たちは現在、back4appデータベースにデータを保存する手続きを進めています。このステップは、 swift swift を使用するか、back4appプラットフォームのアプリのコンソールから直接実装できます。 swift //after setting up your xcode project, calling the following method should save some sample data on your back4app database 1 import parseswift 2 3 func savesampledata() { 4 do { 5 // authors 6 let aaronwriter = try author(name "aaron writer") save() 7 let beatricenovelist = try author(name "beatrice novelist") save() 8 let caseycolumnist = try author(name "casey columnist") save() 9 10 // publishers 11 let acaciapublishings = try publisher(name "acacia publishings") save() 12 let birchdistributions = try publisher(name "birch distributions") save() 13 14 // books with their corresponding isbd 15 let alovestorybook = try book( 16 title "a love story", 17 publisher acaciapublishings, 18 publishingdate date(string "05/07/1998") 19 ) save() 20 relation? add("authors", objects \[aaronwriter]) save() // establishes the m\ n relatin between book and author 21 22 // fetches the isbd associated to alovestorybook and establishes the 1 1 relation 23 if let book = alovestorybook, var isbd = try book fetch(includekeys \["isbd"]) isbd { 24 isbd book = try pointer\<book>(book) 25 = try isbd save() 26 } else { 27 fatalerror() 28 } 29 30 let benevolentelvesbook = try book( 31 title "benevolent elves", 32 publisher birchdistributions, 33 publishingdate date(string "11/30/2008") 34 ) save() 35 relation? add("authors", objects \[beatricenovelist]) save() // establishes the m\ n relatin between book and author 36 37 // fetches the isbd associated to benevolentelvesbook and establishes the 1 1 relation 38 if let book = benevolentelvesbook, var isbd = try book fetch(includekeys \["isbd"]) isbd { 39 isbd book = try pointer\<book>(book) 40 = try isbd save() 41 } else { 42 fatalerror() 43 } 44 45 let canyoubelieveitbook = try book( 46 title "can you believe it", 47 publisher birchdistributions, 48 publishingdate date(string "08/21/2018") 49 ) save() 50 relation? add("authors", objects \[aaronwriter, caseycolumnist]) save() // establishes the m\ n relatin between book and author 51 52 // fetches the isbd associated to canyoubelieveitbook and establishes the 1 1 relation 53 if let book = canyoubelieveitbook, var isbd = try book fetch(includekeys \["isbd"]) isbd { 54 isbd book = try pointer\<book>(book) 55 = try isbd save() 56 } else { 57 fatalerror() 58 } 59 60 // book store 61 guard let safealovestorybook = alovestorybook, 62 let safebenevolentelvesbook = benevolentelvesbook, 63 let safecanyoubelieveitbook = canyoubelieveitbook 64 else { 65 throw nserror( 66 domain bundle main description, 67 code 0, 68 userinfo \[nslocalizeddescriptionkey "failed to unwrapp stored books "] 69 ) 70 } 71 72 // saves the stores together with their 1\ n relation with book's 73 let booksoflove = try bookstore(name "books of love") save() 74 = try booksoflove relation? add("books", objects \[safealovestorybook]) save() 75 76 let fantasybooks = try bookstore(name "fantasy books") save() 77 = try fantasybooks relation? add("books", objects \[safebenevolentelvesbook]) save() 78 79 let generalbooks = try bookstore(name "general books") save() 80 = try generalbooks relation? add("books", objects \[safealovestorybook, safecanyoubelieveitbook]) save() 81 82 } catch let error as parseerror { 83 print("error \n", error message) 84 } catch { 85 print("error \n", error localizeddescription) 86 } 87 } back4app's console //a quick way to insert elements on your back4app database is via the console located in your app’s api section once you are there, you can start running javascript code to save the sample data 1 // authors 2 const aaronwriter = new parse object('author'); 3 aaronwriter set('name', 'aaron writer'); 4 await aaronwriter save(); 5 6 const beatricenovelist = new parse object('author'); 7 beatricenovelist set('name', 'beatrice novelist'); 8 await beatricenovelist save(); 9 10 const caseycolumnist = new parse object('author'); 11 caseycolumnist set('name', 'casey columnist'); 12 await caseycolumnist save(); 13 14 // publishers 15 const acaciapublishings = new parse object('publisher'); 16 acaciapublishings set('name', 'acacia publishings'); 17 await acaciapublishings save(); 18 19 const birchdistributions = new parse object('publisher'); 20 birchdistributions set('name', 'birch distributions'); 21 await birchdistributions save(); 22 23 // books with their corresponding isbd 24 const alovestoryisbd = new parse object('isbd'); 25 alovestoryisbd set('isbn', '9781401211868'); 26 await alovestoryisbd save(); 27 28 const alovestorybook = new parse object('book'); 29 alovestorybook set('title', 'a love story'); 30 alovestorybook set('publisher', acaciapublishings); 31 alovestorybook set('publishingdate', new date('05/07/1998')); 32 alovestorybook set('isbd', alovestoryisbd); 33 const bookarelation = alovestorybook relation("authors"); 34 bookarelation add(aaronwriter); 35 await alovestorybook save(); 36 alovestoryisbd set('book', alovestorybook topointer()); 37 await alovestoryisbd save(); 38 39 const benevolentelvesisbd = new parse object('isbd'); 40 benevolentelvesisbd set('isbn', '9781401211868'); 41 await benevolentelvesisbd save(); 42 43 const benevolentelvesbook = new parse object('book'); 44 benevolentelvesbook set('title', 'benevolent elves'); 45 benevolentelvesbook set('publisher', birchdistributions); 46 benevolentelvesbook set('publishingdate', new date('11/31/2008')); 47 benevolentelvesbook set('isbd', benevolentelvesisbd); 48 const bookbrelation = benevolentelvesbook relation("authors"); 49 bookbrelation add(beatricenovelist); 50 await benevolentelvesbook save(); 51 benevolentelvesisbd set('book', benevolentelvesbook topointer()); 52 await benevolentelvesisbd save(); 53 54 const canyoubelieveitisbd = new parse object('isbd'); 55 canyoubelieveitisbd set('isbn', '9781401211868'); 56 await canyoubelieveitisbd save(); 57 58 const canyoubelieveitbook = new parse object('book'); 59 canyoubelieveitbook set('title', 'can you believe it?'); 60 canyoubelieveitbook set('publisher', birchdistributions); 61 canyoubelieveitbook set('publishingdate', new date('08/21/2018')); 62 canyoubelieveitbook set('isbd', canyoubelieveitisbd); 63 const bookcrelation = canyoubelieveitbook relation("authors"); 64 bookcrelation add(aaronwriter); 65 bookcrelation add(caseycolumnist); 66 await canyoubelieveitbook save(); 67 canyoubelieveitisbd set('book', canyoubelieveitbook topointer()); 68 await canyoubelieveitisbd save(); 69 70 // book store 71 const booksoflovestore = new parse object('bookstore'); 72 booksoflovestore set('name', 'books of love'); 73 const bookstorearelation = booksoflovestore relation("books"); 74 bookstorearelation add(alovestorybook); 75 await booksoflovestore save(); 76 77 const fantasybooksstore = new parse object('bookstore'); 78 fantasybooksstore set('name', 'fantasy books'); 79 const bookstorebrelation = fantasybooksstore relation("books"); 80 bookstorebrelation add(benevolentelvesbook); 81 await fantasybooksstore save(); 82 83 const generalbooksstore = new parse object('bookstore'); 84 generalbooksstore set('name', 'general books'); 85 const bookstorecrelation = generalbooksstore relation("books"); 86 bookstorecrelation add(alovestorybook); 87 bookstorecrelation add(canyoubelieveitbook); 88 await generalbooksstore save(); 3 データのクエリ データベースに作業用のサンプルデータがあると、前述の関係に関連するさまざまな種類のクエリを実行し始めます。 1 1 関係に関するクエリ 2つのデータ型が 1 1 関係を共有している場合(この場合は、 本 本 と isbd isbd )、次のようにして一方から他方を取得できます。 本 本 で関係を実装した方法により、関連する isbd isbd オブジェクトを、クエリの include( ) include( ) メソッドを呼び出すことで簡単に取得できます。では、 isbd isbd を本 a love story 1 let alovestorybookquery = book query("title" == "a love story") include("isbd") // note how we include the isbd with the include( ) method 2 3 let book = try? alovestorybookquery first() // retrieves synchronously the book including its isbd 4 5 alovestorybookquery first { result in // retrieves asynchronously the book including its isbd 6 // handle the result (of type result\<book, parseerror>) 7 } 一方、特定の 本 本 オブジェクトを取得するためのクエリは、次のように実装されます。 isbd isbd の実装を見てみると、関係は isbd isbd プロパティ(型は book book )によって表されていることがわかります。このポインタは、指し示すオブジェクトに関する情報を取得するための一連のメソッドとプロパティを提供します。特に、 fetch( ) fetch( ) メソッドを book book プロパティで呼び出して、関連する 本 本 1 let someisbd isbd 2 3 let book book? = try? someisbd book? fetch() // retrieves synchronously the book asscociated to someisbd 4 5 someisbd book? fetch { result in // retrieves asynchronously the book asscociated to someisbd 6 // handle the result (of type result\<book, parseerror>) 7 } この実装は 1 1 関係に対して唯一ではないことを指摘する必要があります。使用ケースに応じて、 1 1 関係を異なる方法で実装できます。 1\ n 関係を含むクエリ 特定の出版社が発行したすべての本をクエリする必要があるシナリオでは、まず出版社を取得する必要があります。たとえば、最初に出版社 acacia publishings に関連付けられたデータオブジェクトを取得します。この状況に応じて、このプロセスは異なる場合があります。 1 do { 2 // using the object's objectid 3 let acaciapublishings = try publisher(objectid "some object id") fetch() 4 5 // or 6 // using a query 7 let acaciapublishings = try publisher query("name" == "acacia publishings") first() // returns (synchronously) the first publisher with name 'acacia publishings' the constraint is constructed using the == operator provided by the parseswift sdk 8 9 // to be completed below 10 } catch { 11 // hanlde the error (of type parseerror) 12 } 今、私たちは acaciapublishings acaciapublishings , 関連する本を取得するためのクエリを構築できます。 query\<book> クラスをインスタンス化することによってクエリを作成します。この場合、このクラスは query( ) という静的メソッドを使用してインスタンス化されます。 book オブジェクトによって提供されます。このメソッドの(可変)引数は標準の queryconstraint オブジェクトです。したがって、私たちが探している本は次のスニペットで取得されます。 1 do { 2 let acaciapublishings = try publisher query("name" == "acacia publishings") first() // returns the first publisher with name 'acacia publishings' 3 4 let constraint queryconstraint = try "publisher" == publisher 5 let query = book query(constraint) // creates the query to retrieve all book objects where its publisher field equalt to 'acaciapublishings' 6 7 let books \[book] = try query find() // executes the query synchronously 8 9 // books should contain only one element the book 'a love story' 10 } catch { 11 // hanlde the error (of type parseerror) 12 } 上記のスニペットの非同期実装は、次のように記述できます 1 // we retrieve the publisher with name 'acacia publishings' 2 publisher query("name" == "acacia publishings") first { result in 3 switch result { 4 case success(let publisher) 5 guard let constraint queryconstraint = try? "publisher" == publisher else { fatalerror() } 6 7 // then, we retrieve the books with the corresponding constraint 8 book query(constraint) find { result in 9 switch result { 10 case success(let books) 11 // books should contain only one element the book 'a love story' 12 break 13 case failure(let error) 14 // handle the error (of type parseerror) 15 break 16 } 17 } 18 19 case failure(let error) 20 // handle the error (of type parseerror) 21 break 22 } 23 } m\ n関係を含むクエリ(ケース1) このケースを説明するために、次のシナリオを考えます; 特定の日付(例、 01/01/2010 )以降に出版された本を含むすべての店舗をリストしたいと考えています。まず、本を選択するための中間クエリが必要です。次に、店舗をリストするためのメインクエリを構築します。 したがって、本のための最初のクエリを準備します 1 let booksquery = book query("publishingdate" > date(string "01/01/2010")) // we construct the date constraint using the > operator provided by the parseswift sdk 2 3 do { 4 let books = try booksquery find() 5 // to be completed below 6 } catch let error as parseerror { 7 // handle any potential error 8 } catch { 9 // handle any potential error 10 } 次に、ストアのクエリを booksquery booksquery の結果を使用して構築します。メソッド containedin( array ) containedin( array ) は、このケースに必要な制約を返します。 1 let booksquery = book query("publishingdate" > date(string "01/01/2010")) // we construct the date constraint using the > operator provided by the parseswift sdk 2 3 do { 4 let books = try booksquery find() 5 6 // here is where we construct the stores' query with the corresponding constraint 7 let storesquery = bookstore query(try containedin(key "books", array books)) 8 9 let stores = try storesquery find() 10 11 // stores should containt only one element the 'general books' bookstore 12 } catch let error as parseerror { 13 // handle any potential error 14 } catch { 15 // handle any potential error 16 } 同様に、このプロセスを非同期に実装できます。 1 let booksquery = book query("publishingdate" > date(string "01/01/2010")) // we construct the date constraint using the > operator provided by the parseswift sdk 2 3 booksquery find { result in 4 switch result { 5 case success(let books) 6 guard let constraint = try? containedin(key "books", array books) else { fatalerror() } 7 let storesquery = bookstore query(constraint) 8 9 storesquery find { result in 10 switch result { 11 case success(let stores) 12 13 case failure(let error) 14 // handle the error (of type parseerror) 15 } 16 } 17 case failure(let error) 18 // handle the error (of type parseerror) 19 } 20 } m\ n 関係を含むクエリ (ケース 2) 特定の著者、例えば、 aaron writer が書いた本を持つすべての店舗を選択する必要があるとします。これを達成するために、2つの追加のクエリが必要です 著者aaron writerに関連付けられたオブジェクトを取得するためのクエリ ( query\<author> query\<author> )。 著者 aaron writer が書いたすべての本を選択するためのクエリ ( query\<book> query\<book> )。 私たちが探している店舗を選択するためのメインクエリ ( query\<bookstore> query\<bookstore> )。 これらのクエリを実装する手順は、前のものと非常に似ています 1 let authorquery = author query("name" == "aaron writer") // the first query to retrieve the data object associated to 'aaron writer' 2 3 do { 4 let aaronwriter = try authorquery first() 5 6 let booksquery = book query(try containedin(key "authors", array \[aaronwriter])) // the second query to retrieve the books written by 'aaron writer' 7 8 let books = try booksquery find() 9 10 let storesquery = bookstore query(try containedin(key "books", array books)) // the main query to select the stores where the author ('aaron writer') has his books available 11 12 let stores = try storesquery find() 13 14 // stores should contain two items 'books of love' and 'general books' 15 } catch let error as parseerror { 16 // handle the error 17 } catch { 18 // handle the error 19 } 結論 parseswift sdkを使用して、他のデータ型との関係に基づいてアイテムを選択することを可能にするリレーショナルクエリを構築することができました。