サムネイル

注意!!firebaseの仕様が変わってました。(firestore編)

はじめに

おはようございます。こんにちは。こんばんは。
Watatakuです。
今回の書いていく内容なんですけれども、タイトルから分かる通り仕様が変わっていました。
v8までを使用している方は以前の書き方で大丈夫なのですが、これから新規でfirebaseのプロジェクトを始めるときに書き方が変わりますというお話です。
その中でも今回はfirestoreをやっていきます。

firestore

公式ページ

  • firebaseが提供しているNoSQLのデータベース。
  • firebaseには同じくRealTimeDatabaseというものもありますが基本的にはfirestoreの仕様が推奨されている。


create

データの作成は、ドキュメントIDを指定する場合と指定せずに自動採番してもらう方法があります。
ID指定してドキュメントを作成する方法

import { initializeApp } from "firebase/app";
import { doc , setDoc , getFirestore } from "firebase/firestore";

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
// データの書き込み=通信を挟む=非同期処理
await setDoc(doc(db,"users", "000"), {
  address: {
    prefecture: "沖縄",
    region: "沖縄",
  },
  age: 20,
  createdAt: "2020年11月10日 15:00:00 UTC+9",
  friends: ["003"],
  userName: "山田太郎",
});
await setDoc(doc(db,"users", "001"), {
  address: {
    prefecture: "北海道",
    region: "北海道",
  },
  age: 20,
  createdAt: "2020年11月8日 12:00:00 UTC+9",
  friends: [],
  userName: "小島三郎",
});
await setDoc(doc(db,"users", "002"), {
  address: {
    prefecture: "東京",
    region: "関東",
  },
  age: 19,
  createdAt: "2020年11月1日 9:14:00 UTC+9",
  friends: ["001"],
  userName: "山田花子",
});
await setDoc(doc(db,"users", "003"), {
  address: {
    prefecture: "大阪",
    region: "関西",
  },
  age: 50,
  createdAt: "2020年11月10日 15:00:00 UTC+9",
  friends: [""],
  userName: "山田花子",
});

[TIPS]

IDを指定せずに作るパターン

import { initializeApp } from "firebase/app";
import { collection , addDoc , getFirestore } from "firebase/firestore";

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
const userReference = addDoc(collection(db, "users_sub"), {
  address: {
    prefecture: "名古屋",
    region: "中部",
  },
  age: 26,
  createdAt: "2021年1月3日 19:4:00 UTC+9",
  friends: ["004"],
  userName: "小一のしょういち",
});

createだけを見てみても前との書き方の差がありますね。

update

データの更新になります。

import { initializeApp } from "firebase/app";
import { doc. updateDoc, getFirestore } form "firebase/firestore";

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
const userRef = doc(db, "users" , "003")
await updateDoc(userRef, {
  address: {
    prefecture: "群馬",
    region: "北関東",
  },
  age: 27,
  createdAt: "2022年12月2日 19:4:00 UTC+9",
  friends: ["001"],
  userName: "小五のしょうご",
});

delete

ドキュメントの削除についてです。

import { initializeApp } from "firebase/app";
import { doc , deleteDoc, getFirestore } from "firebase/firestore";

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);

// 匿名アカウントの情報を削除します
await deleteDoc(doc(db, "users" , "003");

read

今のデータを見るとこうなっています。

// コレクション
users: {
  // ドキュメント
  "000": {
    // フィールド
    address: {
      prefecture: "沖縄",
      region: "沖縄",
    },
    age: 20,
    createdAt: "2020年11月10日 15:00:00 UTC+9",
    friends: ["003"],
    userName: "山田太郎",
  },
  "001": {
    address: {
      prefecture: "北海道",
      region: "北海道",
    },
    age: 29,
    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: "山田花子",
  },
}

このデータを用いてクエリを投げていきます。

全件取得

import { initializeApp } from "firebase/app";
import {
  doc,
  getDocs,
  getFirestore
} from 'firebase/firestore';

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
const usersRef = doc(db, "users");

getDocs(usersRef).then(snapshot => {
  snapshot.forEach(doc => {
    console.log(`${doc.id}: ${doc.data().userName}`);
  })
})

上記の結果は以下の通り。

000:山田太郎
001:小島三郎
002: 山田花子


where

< : ~より小さい
  • 未成年(20歳未満)のユーザを抽出
import { initializeApp } from "firebase/app";
import {
  collection,
  getDocs,
  getFirestore,
  query,
  where,
} from 'firebase/firestore';

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
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を参照できる

import { initializeApp } from "firebase/app";
import {
  collection,
  documentId,
  getDocs,
  getFirestore,
  query,
  where,
} from 'firebase/firestore';

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
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で参照するときと同様に、オブジェクト名.プロパティ名で参照できる

import { initializeApp } from "firebase/app";
import {
  collection,
  getDocs,
  getFirestore,
  query,
  where,
} from 'firebase/firestore';

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
const usersRef = collection(db, "users");

getDocs(query(usersRef, where("address.prefecture", "==", "東京"))).then(snapshot => {
  snapshot.forEach(doc => {
    console.log(`${doc.id}: ${doc.data().userName}`);
  })
})

上記の結果は以下の通り。

002: 山田花子
!= : 等しくない
  • 東京に住んでいないユーザを抽出
import { initializeApp } from "firebase/app";
import {
  collection,
  getDocs,
  getFirestore,
  query,
  where,
} from 'firebase/firestore';

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
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型は、日付オブジェクトをクエリに利用できる。

import { initializeApp } from "firebase/app";
import {
  collection,
  getDocs,
  getFirestore,
  query,
  where,
} from 'firebase/firestore';

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
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」がフレンドのユーザを抽出
import { initializeApp } from "firebase/app";
import {
  collection,
  getDocs,
  getFirestore,
  query,
  where,
} from 'firebase/firestore';

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
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」のいずれかがフレンドのユーザを抽出
import { initializeApp } from "firebase/app";
import {
  collection,
  getDocs,
  getFirestore,
  query,
  where,
} from 'firebase/firestore';

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
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:右辺のいずれかが含まれている
  • ユーザ名が「山田太郎」もしくは「山田花子」を抽出
import { initializeApp } from "firebase/app";
import {
  collection,
  getDocs,
  getFirestore,
  query,
  where,
} from 'firebase/firestore';

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
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:右辺のいずれも含まれない
  • ユーザ名が「山田太郎」でも「山田花子」でもないユーザを抽出
import { initializeApp } from "firebase/app";
import {
  collection,
  getDocs,
  getFirestore,
  query,
  where,
} from 'firebase/firestore';

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
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
  • 20代のユーザを抽出する
import { initializeApp } from "firebase/app";
import {
  collection,
  getDocs,
  getFirestore,
  query,
  where,
} from 'firebase/firestore';

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
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: 小島三郎

orderBy

ソートはorderByで行う。orderBy("age")とすることで、ageで昇順ソート、orderBy("age", "desc")とすると、ageで降順ソートされる。

年齢を昇順で表示
import { initializeApp } from "firebase/app";
import {
  collection,
  getDocs,
  getFirestore,
  orderBy,
  query,
} from 'firebase/firestore';

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
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歳
年齢を降順で表示
import { initializeApp } from "firebase/app";
import {
  collection,
  getDocs,
  getFirestore,
  orderBy,
  query,
} from 'firebase/firestore';

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
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歳

limit

最大表示件数の指定はlimit()で行う。limit(1)とすると最大1件分、limit(10)とすると最大10件分取得する

import { initializeApp } from "firebase/app";
import {
  collection,
  getDocs,
  getFirestore,
  limit,
  query,
} from 'firebase/firestore';

const firebaseConfig = {
  apiKey: " process.env.API_KEY",
  authDomain: "process.env.AUTH_DOMAIN",
  projectId: "process.env.PROJECT_ID",
  storageBucket: "process.env.STORAGE_BUCKET",
  messagingSenderId: "process.env.MESSAGING_SENDER_ID",
  appId: "process.env.APP_ID",
  measurementId: "process.env.MEASUREMENT_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
const usersRef = collection(db, "users");

getDocs(query(usersRef, limit(1))).then(snapshot => {
  snapshot.forEach(doc => {
    console.log(`${doc.id}: ${doc.data().userName}`);
  })
})

上記の結果は以下の通り。

山田太郎, 20歳

最後に

firebase本当に便利なので使って見てください。
この記事を見てみてfirebaseの設定がわからない方や以前の書き方ってどうだったんだろうと気になるかたは、
以前私がQiitaにまとめた記事がありますので良ければご覧ください。
https://qiita.com/watataku8911/items/ac040f4671c0f9a62bd4

また近いうちに「firebase storage」や「firebase authentication」について書きます。