iOS
...
Data Objects
在iOS应用中使用ParseSwift进行关系数据查询技巧
12 分
关系查询 介绍 在 之前的指南 https //www back4app com/docs/ios/parse swift sdk/data objects/query cookbook 中,我们详细介绍了如何在 back4app 数据库上执行各种查询。在本指南中,我们专注于一种特定类型的查询,该查询涉及具有关系的对象。 先决条件 要完成本教程,您需要: 一个 在 back4app 上创建的应用 一个基本的 ios 应用来测试查询 目标 使用 parseswift sdk parseswift sdk 查询存储在 back4app 数据库中的关系数据。 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 数据库上设置一些数据。我们将存储五种类型的对象: 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关系的查询 给定两个共享 1 1 关系的数据类型(在本例中为 书籍 书籍 和 isbd isbd ),我们可以通过以下方式从一个中检索另一个。我们在 书籍 书籍 中实现的关系允许我们通过在查询上调用 include( ) include( ) 方法简单地检索其相关的 isbd isbd 对象。让我们从书籍 爱情故事 中检索 isbd isbd : 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 属性(类型为 pointer\<book> pointer\<book> )表示。该指针提供了一组方法和属性,以检索有关其指向的对象的信息。特别是,我们在 book book 属性上调用 fetch( ) fetch( ) 方法以获取相关的 书籍 书籍 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> 类来创建查询。在这种情况下,这个类是使用 query( ) query( ) 提供的静态方法实例化的,来自 book book 对象。此方法的 (可变参数) 参数是标准的 queryconstraint 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 。为了实现这一点,我们需要两个额外的查询: 一个查询( query\<author> query\<author> )以获取与作者 aaron writer 相关的对象。 一个查询( query\<book> query\<book> )以选择所有由 aaron writer 写的书籍。 主要查询( 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 parseswift sdk ,我们能够构建关系查询,使我们能够根据它们与其他数据类型的关系类型选择项目。