質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Cloud Firestore

Cloud Firestore は、自動スケーリングと高性能を実現し、アプリケーション開発を簡素化するように構築された NoSQLドキュメントデータベースです。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

0回答

1085閲覧

Firestoreを配列内の構造体の値で検索する方法

wine

総合スコア18

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Cloud Firestore

Cloud Firestore は、自動スケーリングと高性能を実現し、アプリケーション開発を簡素化するように構築された NoSQLドキュメントデータベースです。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2020/03/02 13:31

編集2020/03/04 02:28

前提・実現したいこと

swift

1struct Box { 2 let fruits: [Fruit] 3// 以下略 4} 5 6struct Fruit { 7 let type: String // "みかん" "りんご" など 8// 以下略 9}

上のような構造体Boxが入ったドキュメントのコレクションboxesを作成しました。
タイプが"みかん"のフルーツを含むBoxのリストを取得したいのですが、うまくいきません。

試したこと

swift

1let DB = Firestore.firestore() 2DB.collection("boxes").whereField("fruits.type", arrayContains: "みかん").getDocuments() 3DB.collection("boxes").whereField("fruits.type", isEqualTo: "みかん").getDocuments() 4DB.collection("boxes").whereField("fruits.`${index}`.type", isEqualTo: "みかん").getDocuments() 5DB.collection("boxes").whereField("fruits", arrayContains: "type.みかん").getDocuments()

4つともクエリを打ち、URLでインデックスを作成し、再度クエリを打ったのですが、結果は空のドキュメント配列でした。

よろしくお願いいたします。

追記

上記は簡易的な例で、実際のアプリはもっと複雑なのですが、公開ができないので、テストアプリを作りました。
firestoreのスクショ
firestoreの様子

テストアプリのViewController(コードが雑なのはご容赦ください)

swift

1import UIKit 2import Firebase 3 4class ViewController: UIViewController { 5 6 let DB = Firestore.firestore() 7 8 override func viewDidLoad() { 9 super.viewDidLoad() 10 11 let b = UIButton(frame: CGRect(x: 100, y: 200, width: 100, height: 50)) 12 b.backgroundColor = .red 13 view.addSubview(b) 14 b.addTarget(self, action: #selector(tapRed), for: .touchUpInside) 15 16 let b2 = UIButton(frame: CGRect(x: 100, y: 300, width: 100, height: 50)) 17 b2.backgroundColor = .blue 18 view.addSubview(b2) 19 b2.addTarget(self, action: #selector(tapBlue), for: .touchUpInside) 20 } 21 22 @objc func tapRed() { 23 let b = Box(name: "はこ1", fruits: [Fruit(type: "mikan"), Fruit(type: "apple")]).encoded() 24 let r = DB.collection("boxes").document("b1") 25 r.setData(b, completion: nil) 26 27 let b2 = Box(name: "はこ2", fruits: [Fruit(type: "apple")]).encoded() 28 let r2 = DB.collection("boxes").document("b2") 29 r2.setData(b2, completion: nil) 30 31 let b3 = Box(name: "はこ3", fruits: [Fruit(type: "mikan")]).encoded() 32 let r3 = DB.collection("boxes").document("b3") 33 r3.setData(b3, completion: nil) 34 } 35 36 @objc func tapBlue() { 37 // みかんの入った箱(b1とb3)だけ取りたい 38 let r = DB.collection("boxes").whereField("fruits", arrayContains: "type.mikan") 39 r.getDocuments() { (snap, error) in 40 print("結果", snap?.documents, error) 41 } 42 } 43} 44 45struct Box { 46 let name: String 47 let fruits: [Fruit] 48 49 func encoded() -> [String:Any] { 50 let fs = fruits.map({$0.encoded()}) 51 return ["name": name, "fruits": fs] 52 } 53} 54 55struct Fruit { 56 let type: String 57 func encoded() -> [String:Any] { 58 return ["type": type] 59 } 60}

どうしてもできない場合、fruitType配列をBoxに持たせようと思っていますが、ドキュメント内でデータが重複するので、できれば避けたいところです。
よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hayabusabusash

2020/03/04 00:27

Firestore側にデータは保存されていますか? Firestoreの画面のスクショなんかを貼っていただけると、何かわかるかもしれません。
hayabusabusash

2020/03/04 02:28

追記ありがとうございます ????‍♂️ Firestoreからデータを読み込む部分を以下のようにしたらどうなりますか? let r = DB.collection("boxes").whereField("fruits", arrayContains: "mikan")
wine

2020/03/04 02:31

以下のような結果が返ってきました 結果 Optional([]) nil
hayabusabusash

2020/03/04 02:40

なるほど、マップの配列になっているのがちょっと厄介かもしれませんね... 単純にfruitsフィールドをStringの配列にするとかは無理そうですか?
wine

2020/03/04 02:44 編集

実際のアプリだと、fruitにあたる構造体が結構大きいので、難しいです… 検索クエリがないとなると、やはりfruitType配列を別に持つのがベストでしょうか。。。
hayabusabusash

2020/03/04 02:49

Firestoreの設計にはそこまで詳しくないので、ちょっとベストかは分かりませんが... 自分ならBoxには入っているフルーツの構造体をそのまま入れるのではなくて名前だけを持たせておいて、 別のコレクションにフルーツ本体の構造体を入れておくという構成にすると思います。 そうすると今よりは簡単にクエリの処理が書けると思います。
wine

2020/03/04 03:04

すみません…。無理に簡易化させようと、果物と箱で例えた例が悪かったかもです。 実際のアプリはツイートと、中に複数のコンテンツ(ID、プレースホルダーの色、画像か動画かリンクか、縦横比など)があるようなデータなのです。 ツイート一覧を取得して、一時的な情報を素早く表示したいので、他のコレクションにして、再度取得して時間がかかるのは避けたいようなアプリです。 例えが悪く誤解させてしまい、申し訳ありません。。。
hayabusabusash

2020/03/04 03:12

いえ、こちらこそちゃんとした回答ができず申し訳ないです ????‍♂️ ちょっとどんな状況なのかイマイチ掴めないので、 もし可能ならどんな構成になっているのか追記していただきたいです。 それが無理なら自分では力になれそうにないかもしれません、申し訳ないです...
wine

2020/03/04 03:21

実際の構成は公開できないので、すみません。 やはり、構造体配列を使った検索クエリは無さそうという点は変わらないので、クエリ用のテキスト配列を持たせる方向でいこうと思います。 また、返信が早くて適確で、大変助かりました! あまり要領を得ない質問やコメントだったかもしれませんが、お付き合いいただき感謝します!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問