Help us understand the problem. What is going on with this article?

Swiftでデータベースを使おう!②(関連付け・検索)

More than 3 years have passed since last update.

【お知らせ】Swift3に対応しました!(2017/02/23更新)

【Swift×mBaaS】シリーズ概要

  • Swiftでニフティクラウドmobile backend(通称:mBaaS)を使ってSwiftで開発を始めたい人向けのドキュメントです。
  • ニフティクラウドmobile backendのiOS(Objectiv-C SDK)用ドキュメントSwift用に書き換えて動かしてみたものをまとめました。
  • 初心者でもわかりやすいよう心掛けて作っていますが、わかりにくい部分がありましたらコメントをいただければ訂正しますのでお気軽にご意見をお願いします^^*
  • 今回は<データストア編②>として関連付け(ポインタ・リレーション)検索標準クラスの検索検索条件クエリの合成です!

事前準備のお願い

Swiftでデータベースを使おう!

オブジェクトの関連付け

ポインタ

  • NCMBObjectのインスタンスに、別のNCMBObjectを設定すると、設定したNCMBObjectへのポインタが設定されます。
  • ポインタ先のオブジェクトがデータストアに登録されていない場合は、ポインタ元のオブジェクトを保存する前に自動で作成されるようになっています。
  • 以下の例はobjectクラスのpointerフィールドでchildクラスを参照するサンプルです。
Swift3
// childクラスを作成(keyフィールドにvalueの値を保存)
let pointer = NCMBObject(className: "child")
pointer?.setObject("value", forKey : "key")
pointer?.save(nil) /*同期処理*/
// objectクラスを作成
let object = NCMBObject(className: "object")
// ポインターの設定
object?.setObject(pointer, forKey: "pointer")
object?.saveInBackground({(error) in
    if (error != nil) {
        // 保存に失敗した場合の処理
    }else{
        // 保存に成功した場合の処理
    }
})
Swift2
// childクラスを作成(keyフィールドにvalueの値を保存)
let pointer = NCMBObject(className: "child")
pointer.setObject("value", forKey : "key")
pointer.save(nil) /*同期処理*/
// objectクラスを作成
let object = NCMBObject(className: "object")
// ポインターの設定
object.setObject(pointer, forKey: "pointer")
object.saveInBackgroundWithBlock({(NSError error) in
    if (error != nil) {
        // 保存に失敗した場合の処理
    }else{
        // 保存に成功した場合の処理
    }
})

リレーション

  • ポインタは1つのオブジェクトへの参照しか持つことができないので、複数参照を行いたい場合にはリレーションを利用します。
  • リレーションは特定クラスの複数オブジェクトと関連づけることができます。
  • リレーションの追加・削除にはNCMBRelationクラスを利用します。
  • ポインタでは参照先のオブジェクトが登録されていない場合、自動で作成されましたが、リレーションの場合は自動的に保存されることはありません。
  • 以下の例は、PostクラスのcommentsフィールドにNCMBRelationを作成してCommentクラスの2つのオブジェクト(comment1 とcomment2)をリレーション先として設定しているサンプルです。
Swift3
// リレーション元のオブジェクトを作成
let post = NCMBObject(className: "Post")
post?.setObject("about mobile backend", forKey: "title")

// リレーション先1のオブジェクトを作成
let comment1 = NCMBObject(className: "Comment")
comment1?.setObject("good", forKey: "text")
comment1?.save(nil)

// リレーション先2のオブジェクトを作成
let comment2 = NCMBObject(className: "Comment")
comment2?.setObject("bad", forKey: "text")
comment2?.save(nil)

// commentsフィールドにNCMBRelationを作成
let relation = NCMBRelation(className: post, key: "comments")

// リレーションオブジェクトを追加
relation?.add(comment1)
relation?.add(comment2)

// リレーションを設定したオブジェクトを保存
post?.save(nil)
Swift2
// リレーション元のオブジェクトを作成
let post = NCMBObject(className: "Post")
post.setObject("about mobile backend", forKey: "title")

// リレーション先1のオブジェクトを作成
let comment1 = NCMBObject(className: "Comment")
comment1.setObject("good", forKey: "text")
comment1.save(nil)

// リレーション先2のオブジェクトを作成
let comment2 = NCMBObject(className: "Comment")
comment2.setObject("bad", forKey: "text")
comment2.save(nil)

// commentsフィールドにNCMBRelationを作成
let relation = NCMBRelation(className: post, key: "comments")

// リレーションオブジェクトを追加
relation.addObject(comment1)
relation.addObject(comment2)

// リレーションを設定したオブジェクトを保存
post.save(nil)

オブジェクトの検索

  • 検索には、NCMBQueryクラスを利用します。
  • 下記の例は、条件なしで検索を行うサンプルです。クラスのデータが全件検索されます。
Swift3
// TestClassクラスを検索するNCMBQueryを作成
let query = NCMBQuery(className: "TestClass")

/** 条件を入れる場合はここに書きます **/

// データストアの検索を実施
query?.findObjectsInBackground({(objects, error) in
    if (error != nil){
        // 検索失敗時の処理
    }else{
        // 検索成功時の処理
        print(objects! as! [NCMBObject]) // (例)検索結果を表示する
    }
})
Swift2
// TestClassクラスを検索するNCMBQueryを作成
let query = NCMBQuery(className: "TestClass")

    /** 条件を入れる場合はここに書きます **/

// データストアの検索を実施
query.findObjectsInBackgroundWithBlock({(NSArray objects, NSError error) in
    if (error != nil){
        // 検索失敗時の処理

    }else{
        // 検索成功時の処理
        print(objects) // (例)検索結果を表示する
    }
})
  • 「/** 条件を入れる場合はここに書きます **/」とあるところに条件を入れて検索できます。
  • 条件については後の項目に書きます。

標準クラスの検索

  • 標準で存在するクラスは以表の5つあります。
クラス名 役割
user 会員管理クラス
role データストアのデフォルトクラス(会員グルーピング)
installation データストアのデフォルトクラス(端末情報一覧)
file ファイルストアのクラス  
push プッシュ通知のクラス
  • これらのクラス名を使って、データストアに新規のクラスを作成しようとするとエラーになります。
  • 上記のクラス名を指定して、同様にオブジェクト検索を行うことができます。userクラスの検索の場合は以下のようになります。
Swift_共通
let query = NCMBQuery(className: "user")
  • userクラスの場合はNCMBUserオブジェクトを使って次のようにクエリを作成することも出来ます。
Swift_共通
let query = NCMBUser.query()

補足

  • 各データにはACL(アクセス権限)設定機能があります。デフォルトでは権限は設定されていません。(誰でも読み書き可能)
  • 会員クラス(user)に関してはユーザー本人しか読み書きが行えない設定になっています。上記サンプルを実行する前にダッシュボード上からACL設定を確認してください。詳しくは<データストア編③>で説明します。

検索条件の設定

以下は検索条件のサンプルです。

Swift3
// keyフィールドの値がvalueと一致するデータを検索する条件
query?.whereKey("key", equalTo: "value")
// ["A","B","C"]と一致する配列を検索する条件
query?.whereKey("array", equalTo:["A","B","C"])
// "A"と"B"の両方の値が入っている配列を検索する条件
query?.whereKey("array", containsAllObjectsIn: ["A","B"])
Swift2
// keyフィールドの値がvalueと一致するデータを検索する条件
query.whereKey("key", equalTo: "value")
// ["A","B","C"]と一致する配列を検索する条件
query.whereKey("array", equalTo:["A","B","C"])
// "A"と"B"の両方の値が入っている配列を検索する条件
query.whereKey("array", containsAllObjectsInArray: ["A","B"])
  • whereKey:equalToメソッドなど以外にも検索条件を設定することが可能です。

ポインタ検索条件の設定

objectクラスのpointerフィールドに設定されたポインタ(childクラスのデータ)を検索します。※関連付け(ポインタ)で作成したサンプルでで試すことができます。

Swift3
// childクラスを検索するNCMBQueryを作成
let innerQuery = NCMBQuery(className:"child")
// keyフィールドの値でvalueと一致するデータを検索する条件を設定
innerQuery?.whereKey("key", equalTo:"value")
// objectクラスを検索するNCMBQueryを作成
let query = NCMBQuery(className:"object")
// innerQueryの条件と一致するデータをpointerフィールが参照しているchildクラスのデータから検索する条件を設定
query?.whereKey("pointer", matchesQuery:innerQuery)
// 設定した条件で検索
query?.findObjectsInBackground({(objects, error) in
    if (error != nil){
        // 検索失敗時の処理
    }else{
        // 検索成功時の処理
        print(objects! as! [NCMBObject])
    }
})
Swift2
// childクラスを検索するNCMBQueryを作成
let innerQuery = NCMBQuery(className:"child")
// keyフィールドの値でvalueと一致するデータを検索する条件を設定
innerQuery.whereKey("key", equalTo:"value")
// objectクラスを検索するNCMBQueryを作成
let query = NCMBQuery(className:"object")
// innerQueryの条件と一致するデータをpointerフィールが参照しているchildクラスのデータから検索する条件を設定
query.whereKey("pointer", matchesQuery:innerQuery)
// 設定した条件で検索
query.findObjectsInBackgroundWithBlock({(NSArray objects, NSError error) in
    if (error != nil){
        // 検索失敗時の処理

    }else{
        // 検索成功時の処理
        print(objects) 
    }
})

リレーションの検索条件の設定

  • Postクラスのcommentsフィールドに設定されたリレーションを検索します。
  • !!注意!!以下のプログラムの動作確認はできておりません。。。(2016/2/17現在)
    • SDKのせいなのか??エラー原因は調査中です。やはりSwiftにちゃんと対応したSDKではないせいなのかな...;_;
    • 対処方法が見つかり次第更新します。
Swift
let post = NCMBObject(className:"Post")
// Postクラスのcommentsフィールドにリレーションを作成
let relation = NCMBRelation(className: post, key: "comments")
// リレーションを検索するクエリを取得
let query = relation.query()                             // ←この行を実行中にエラー発生...

クエリの合成

検索条件としてand検索やor検索も簡単に指定できます。

and検索

  • 条件を複数指定するとand検索をすることができます。
Swift3
//intフィールドの値が30より上で、50未満の値を検索する条件が設定される
query?.whereKey("int", greaterThan:30)
query?.whereKey("int", lessThan:50)
Swift2
//intフィールドの値が30より上で、50未満の値を検索する条件が設定される
query.whereKey("int", greaterThan:30)
query.whereKey("int", lessThan:50)

or検索

  • or検索にはorQueryWithSubqueriesメソッドを利用します。
Swift3
let className = "test"
let query1 = NCMBQuery(className:className)
query1?.whereKey("key1", equalTo:"value1")
let query2 = NCMBQuery(className:className)
query2?.whereKey("key2", equalTo:"value2")
//key1がvalue1であるか、key2がvalue2であるデータを検索する条件
let query = NCMBQuery.orQuery(withSubqueries: [query1!,query2!])
Swift2
let className = "test"
let query1 = NCMBQuery(className:className)
query1.whereKey("key1", equalTo:"value1")
let query2 = NCMBQuery(className:className)
query2.whereKey("key2", equalTo:"value2")
//key1がvalue1であるか、key2がvalue2であるデータを検索する条件
let query = NCMBQuery.orQueryWithSubqueries([query1,query2])

参考

natsumo
ニフクラ mobile backend の使い方をまとめています。
https://github.com/natsumo/
fjct
クラウド・IoT 関連サービスを開発・提供している企業です。(こちらは、富士通クラウドテクノロジーズの有志にて運営しております。)
https://fjct.fujitsu.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした