【Firebase】Cloud Firestore クエリ まとめ
ウェブ版 CloudFirestoreのクエリ備忘録
日本語版公式ドキュメントに載っていないものがいくつかあったので、まとめてみた。
※コレクショングループについては書いていません。
更新情報
前提となるデータ構造
Firestoreの中身は以下を想定
// コレクション
users: {
// ドキュメント
"000": {
// フィールド
address: {
prefecture: "沖縄",
region: "沖縄",
},
age: 20,
createdAt: 2020年11月10日 15:00:00 UTC+9,
friends: ["003"],
userName: "山田太郎",
},
"001": {
address: {
prefecture: "北海道",
region: "北海道",
},
age: 20,
createdAt: 2020年11月8日 12:00:00 UTC+9,
friends: [],
userName: "小島三郎",
},
"002": {
address: {
prefecture: "東京",
region: "関東",
},
age: 19,
createdAt: 2020年11月1日 9:14:00 UTC+9,
friends: ["001"],
userName: "山田花子",
},
}
where:クエリ演算子
利用可能なクエリ一覧
演算子 | 説明 | 書き方 |
---|---|---|
< |
~より小さい | .where("age", "<", 25) |
<= |
~以下 | .where("age", "<=", 25) |
== |
~と等しい | .where("userName", "==", "山田太郎") |
!= |
~と等しくない | .where("userName", "!=", "山田太郎") |
> |
~より大きい | .where("age", ">", 20) |
>= |
~以上 | .where("age", ">=", 20) |
array-contains |
配列内に、右辺の要素が含まれている | .where("friends", "array-contains", "003") |
array-contains-any |
配列内に、右辺の要素のいずれかが含まれている | .where("friends", "array-contains-any", ["002", "003"]) |
in |
右辺のいずれかが含まれている | .where("friends", "in", ["001", "002"]) |
not-in |
右辺のいずれも含まれない | .where("friends", "not-in", ["001", "002"]) |
<
:~より小さい
未成年(20歳未満)のユーザを抽出
const db = firebase.firestore();
db.collection("users").where("age", "<", 20).get().then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
import {
collection,
getDocs,
getFirestore,
query,
where,
} from 'firebase/firestore';
const db = getFirestore();
const usersRef = collection(db, "users");
getDocs(query(usersRef, where("age", "<", 20))).then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
上記の結果は以下の通り。
002: 山田花子
<=
:~以下
ユーザIDが001以下のユーザを抽出
firebase.firestore.FieldPath.documentId()
でドキュメントIDを参照できる
const db = firebase.firestore();
db.collection("users").where(firebase.firestore.FieldPath.documentId(), "<=", "001").get().then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
import {
collection,
documentId,
getDocs,
getFirestore,
query,
where,
} from 'firebase/firestore';
const db = getFirestore();
const usersRef = collection(db, "users");
getDocs(query(usersRef, where(documentId(), "<=", "001"))).then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
上記の結果は以下の通り。
000: 山田太郎
001: 小島三郎
==
:~と等しい
東京在住のユーザを抽出
フィールド内のオブジェクトにあるプロパティはjsで参照するときと同様に、オブジェクト名.プロパティ名
で参照できる
const db = firebase.firestore();
db.collection("users").where("address.prefecture", "==", "東京").get().then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
import {
collection,
getDocs,
getFirestore,
query,
where,
} from 'firebase/firestore';
const db = getFirestore();
const usersRef = collection(db, "users");
getDocs(query(usersRef, where("address.prefecture", "==", "東京"))).then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
上記の結果は以下の通り。
002: 山田花子
!=
:~と等しくない
東京に住んでいないユーザを抽出
const db = firebase.firestore();
db.collection("users").where("address.prefecture", "!=", "東京").get().then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
import {
collection,
getDocs,
getFirestore,
query,
where,
} from 'firebase/firestore';
const db = getFirestore();
const usersRef = collection(db, "users");
getDocs(query(usersRef, where("address.prefecture", "!=", "東京"))).then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
上記の結果は以下の通り。
000: 山田太郎
001: 小島三郎
>=
:~以上
作成日が2020年11月9日以降のユーザを抽出
FirebaseのTimestamp型は、日付オブジェクトをクエリに利用できる
// 2020年11月9日の日付インスタンスを生成
const targetDate = new Date("2020-11-09");
const db = firebase.firestore();
db.collection("users").where("createdAt", ">=", targetDate).get().then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
import {
collection,
getDocs,
getFirestore,
query,
where,
} from 'firebase/firestore';
const db = getFirestore();
const usersRef = collection(db, "users");
// 2020年11月9日の日付インスタンスを生成
const targetDate = new Date("2020-11-09");
getDocs(query(usersRef, where("createdAt", ">=", targetDate))).then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
上記の結果は以下の通り。
000: 山田太郎
array-contains
:配列内に、右辺の要素が含まれている
ユーザID「003」がフレンドのユーザを抽出
const db = firebase.firestore();
db.collection("users").where("friends", "array-contains", "003").get().then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
import {
collection,
getDocs,
getFirestore,
query,
where,
} from 'firebase/firestore';
const db = getFirestore();
const usersRef = collection(db, "users");
getDocs(query(usersRef, where("friends", "array-contains", "003"))).then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
上記の結果は以下の通り。
000: 山田太郎
array-contains-any
:配列内に、右辺の要素のいずれかが含まれている
ユーザID「002, 003, 004」のいずれかがフレンドのユーザを抽出
const db = firebase.firestore();
db.collection("users").where("friends", "array-contains-any", ["001", "002", "003"]).get().then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
import {
collection,
getDocs,
getFirestore,
query,
where,
} from 'firebase/firestore';
const db = getFirestore();
const usersRef = collection(db, "users");
getDocs(query(usersRef, where("friends", "array-contains-any", ["001", "002", "003"]))).then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
上記の結果は以下の通り。
000: 山田太郎
in
:右辺のいずれかが含まれている
ユーザ名が「山田太郎」もしくは「山田花子」を抽出
const db = firebase.firestore();
db.collection("users").where("userName", "in", ["山田太郎", "山田花子"]).get().then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
import {
collection,
getDocs,
getFirestore,
query,
where,
} from 'firebase/firestore';
const db = getFirestore();
const usersRef = collection(db, "users");
getDocs(query(usersRef, where("userName", "in", ["山田太郎", "山田花子"]))).then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
上記の結果は以下の通り。
000: 山田太郎
002: 山田花子
not-in
:右辺のいずれも含まれない
ユーザ名が「山田太郎」でも「山田花子」でもないユーザを抽出
const db = firebase.firestore();
db.collection("users").where("userName", "not-in", ["山田太郎", "山田花子"]).get().then(snapShot => {
snapShot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
import {
collection,
getDocs,
getFirestore,
query,
where,
} from 'firebase/firestore';
const db = getFirestore();
const usersRef = collection(db, "users");
getDocs(query(usersRef, where("userName", "not-in", ["山田太郎", "山田花子"]))).then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
上記の結果は以下の通り。
001: 小島三郎
複合クエリ(And検索)
.where().where()
のようにつなげることでAnd検索が可能
const db = firebase.firestore();
db.collection("users").where("age", ">=", 20).where("age", "<=", 29).get().then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
import {
collection,
getDocs,
getFirestore,
query,
where,
} from 'firebase/firestore';
const db = getFirestore();
const usersRef = collection(db, "users");
getDocs(query(usersRef, where("age", ">=", 20), where("age", "<=", 29))).then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
上記の結果は以下の通り。
000: 山田太郎
001: 小島三郎
ORクエリ
or(where(), where())
のようにすることでOR検索が可能
import {
collection,
getDocs,
getFirestore,
query,
where,
or
} from 'firebase/firestore';
const db = getFirestore();
const usersRef = collection(db, "users");
getDocs(query(usersRef, or(where("userName", "==", "山田太郎"), where("age", "==", 19)))).then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
上記の結果は以下の通り。
000: 山田太郎
002: 山田花子
orderBy:並び替え
ソートはorderBy
で行う。orderBy("age")
とすることで、ageで昇順ソート、orderBy("age", "desc")
とすると、ageで降順ソートされる。
年齢を昇順で表示
const db = firebase.firestore();
db.collection("users").orderBy("age").get().then(snapshot => {
snapshot.forEach(doc => {
const data = doc.data()
console.log(`${data.userName}, ${data.age}歳`);
})
})
import {
collection,
getDocs,
getFirestore,
orderBy,
query,
} from 'firebase/firestore';
const db = getFirestore();
const usersRef = collection(db, "users");
getDocs(query(usersRef, orderBy("age"))).then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
上記の結果は以下の通り。
山田花子, 19歳
山田太郎, 20歳
小島三郎, 29歳
年齢を降順で表示
const db = firebase.firestore();
db.collection("users").orderBy("age", "desc").get().then(snapshot => {
snapshot.forEach(doc => {
const data = doc.data()
console.log(`${data.userName}, ${data.age}歳`);
})
})
import {
collection,
getDocs,
getFirestore,
orderBy,
query,
} from 'firebase/firestore';
const db = getFirestore();
const usersRef = collection(db, "users");
getDocs(query(usersRef, orderBy("age", "desc"))).then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
上記の結果は以下の通り。
小島三郎, 29歳
山田太郎, 20歳
山田花子, 19歳
複数条件でソート
orderBy().orderBy()
とすることで、1つ目のordeBy()
の項目が等しかったら、2つ目のorderBy()
の項目で並び替えが行われる
limit:最大表示件数
最大表示件数の指定はlimit()
で行う。limit(1)
とすると最大1件分、limit(10)
とすると最大10件分取得する
const db = firebase.firestore();
db.collection("users").limit(1).get().then(snapshot => {
snapshot.forEach(doc => {
const data = doc.data()
console.log(`${data.userName}, ${data.age}歳`);
})
})
import {
collection,
getDocs,
getFirestore,
limit,
query,
} from 'firebase/firestore';
const db = getFirestore();
const usersRef = collection(db, "users");
getDocs(query(usersRef, limit(1))).then(snapshot => {
snapshot.forEach(doc => {
console.log(`${doc.id}: ${doc.data().userName}`);
})
})
上記の結果は以下の通り。
山田太郎, 20歳
count:集計クエリ
Firestoreのドキュメントの数を集計するにはgetCountFromServer
を利用する
import {
collection,
getDocs,
getFirestore,
getCountFromServer,
} from 'firebase/firestore';
const db = getFirestore();
const usersRef = collection(db, "users");
getCountFromServer(usersRef).then(snapshot => {
console.log(snapshot.data().count)
})
上記の結果は以下の通り。
3
できないことまとめ
コレクションやドキュメントに対するワイルドカード
以下のようなワイルドカードは不可
const db = firebase.firestore();
db.collection("users").document("*").where( /* 以下省略 */
フィールド内のオブジェクトのキーに対するクエリ
今回のDB構造でいう、addressに対してのクエリはできない
例えば、オブジェクトのキーをエポック秒(UNIX時間)にしたとして、一定の時刻以下のマップを持つユーザ、のようなクエリはできない
// DB構造
users: {
"004": {
"1577804400": {
"hoge": "fuga",
}
}
}
// 上記の1577804400に対するクエリはできない
Discussion