# ソースコードの移行

このドキュメントでは、ニフクラ mobile backendからFirebase Firestoreにソースコードを移行する手順を解説しています。

具体的には、ニフクラ mobile backendの基本的な初期化、データの書き込み、および読み込み処理を例にとり、これらの処理をFirebase Firestoreのコードにどのように変換・適用するかを説明します。

また、本ドキュメントで扱うコードのオリジナルプロジェクトは、ニフクラ mobile backendとFirebase Firestoreをそれぞれ使用した二つのバージョンで、GitHubリポジトリにて公開しています。

{% embed url="<https://github.com/monaca-samples/ncmb-datastore-basic>" %}

{% embed url="<https://github.com/monaca-samples/firestore-basic>" %}

### **初期化**

#### **NCMB データストアの初期化**:

NCMBでは、アプリケーションキーとクライアントキーを用いてサービスを初期化します。これらのキーは、NCMBの管理画面から取得することができます。

```javascript
const NCMB_APPLICATION_KEY = YOUR_APPLICATION_KEY;
const NCMB_CLIENT_KEY = YOUR_CLIENT_KEY;

const ncmb = new window.NCMB(NCMB_APPLICATION_KEY, NCMB_CLIENT_KEY);
```

`window.NCMB` オブジェクトを作成し、その中にアプリケーションキーとクライアントキーを渡すことで、NCMBの各種機能を使用できるようになります。

#### **Firestoreの初期化:**

Firestoreを使用するには、まずFirebaseのSDKをインポートし、Firebaseプロジェクトの設定を行います。

ウェブアプリの設定情報には、Firebaseコンソールから取得した設定情報を使用します。ウェブアプリの登録と設定情報の取得手順は、[こちら](https://ja.docs.monaca.io/external-service-integration-guide/firebase/app-registration#webuapurinotono)を確認してください。

```javascript
// FirebaseのSDKをインポート
import { initializeApp } from "https://www.gstatic.com/firebasejs/10.7.0/firebase-app.js";
import { getFirestore, collection, addDoc, getDocs, doc, updateDoc, query, limit} from "https://www.gstatic.com/firebasejs/10.7.0/firebase-firestore.js";

const firebaseConfig = {
　　　　　// Firebase ウェブアプリの設定情報
};

// Firebaseの初期化
const app = initializeApp(firebaseConfig);

// Firestoreのインスタンスを取得
const db = getFirestore();
```

ここでのポイントは、Firestoreを使うためには、まずFirebaseアプリのインスタンスを初期化し（`initializeApp`）、その後にFirestoreのインスタンス（`getFirestore`）を取得する必要があることです。`firebaseConfig` には、Firebaseプロジェクトの設定情報を設定します。

***

### **書き込み**

#### **NCMBでの書き込み処理**:

NCMBでは、`new Records()` を使用して新しいレコードを作成し、`.set()` メソッドで各フィールドにデータを設定します。レコードが新規か既存かによって処理が異なります。

* **新規レコードの場合**：`.save()` メソッドを使用してデータを保存します。
* **既存レコードの場合**：レコードのIDを設定し、`.update()` メソッドで更新します

```javascript
const onClickSave = async function() {
    for (const record of records) {
        // データベースに保存するための新しいレコードを作成
        const recordData = new Records();
        let saveOrUpdatePromise;

        // データを設定
        recordData.set("date", record.data.date)
            .set("item", record.data.item)
            .set("price", record.data.price);

        if (record.id) {
            // 既存のレコードの場合、IDを設定し更新処理を行う
            recordData.set("objectId", record.id);
            saveOrUpdatePromise = recordData.update();
        } else {
            // 新規のレコードの場合、保存処理を行う
            saveOrUpdatePromise = recordData.save();
        }

        try {
            // データベースに保存または更新
            await saveOrUpdatePromise;
            console.log("データが正常に保存または更新されました。");
        } catch (error) {
            console.error("データの保存または更新に失敗しました:", error);
        }
    }
}
```

**Firestoreでの書き込み処理**:

Firestoreでは、`addDoc()` と `updateDoc()` メソッドを使用してデータを保存または更新します。これらはFirebaseのFirestoreライブラリから提供されています。

* **新規レコードの場合**：`addDoc()` メソッドを使用して新しいドキュメントを作成し、データを保存します。
* **既存レコードの場合**：`doc()` でドキュメントの参照を取得し、`updateDoc()` で更新します。

```javascript
const onClickSave = async () => {
    for (const record of records) {
        try {
            if (record.id) { // IDがある場合は更新
                // レコードのIDを使ってFirebaseデータベース内のドキュメントへの参照を取得します。
                const recordRef = doc(db, "records", record.id);
                
                // 取得した参照に対して、レコードのデータで更新を行います。
                await updateDoc(recordRef, record.data);
                console.log("データが正常に更新されました。");
            } else {
                // レコードに 'id' プロパティが存在しない場合、新しいドキュメントを作成します。
                const docRef = await addDoc(collection(db, "records"), record.data);
                record.id = docRef.id;
                console.log("データが正常に作成されました。");
            }

        } catch (error) {
            console.error("データの保存または更新に失敗しました:", error);
        }
    }
};
```

***

### **読み込み**

#### NCMB での読み込み処理:

NCMBでは、データを読み込むには、対象のデータストアクラス（例では`Records`）を使用し、`fetchAll()` メソッドでデータを取得します。ここでは、最大10件のデータを取得しています。

```javascript
const onClickLoad = async function () {
    try {
        // データベースからデータを取得
        const results = await Records.limit(10).fetchAll();
        records = results.map(result => ({
            id: result.get("objectId"),
            data: {
                date: result.get("date"),
                item: result.get("item"),
                price: result.get("price")
            }
        }));

        // テーブルの中身を空にする
        const tableBody = document.getElementById("data_table").tBodies[0];
        tableBody.innerHTML = '';
        
        // recordsに入っているデータをテーブルに追加
        records.forEach(doc => renderTableRow(doc.data));
    } catch (error) {
        alert("データの読み込みに失敗しました。エラーコード: " + error);
    }
}
```

このコードでは、取得したデータを`map`関数を使って加工し、テーブルに表示しています。

#### Firestoreでの読み込み処理:

Firestoreでは、`getDocs()` 関数と `collection()` 関数を使用してデータを取得します。`getDocs()` 関数は、指定したコレクション内のドキュメントのスナップショットを返します。Firestoreの場合も、取得したデータを`map`関数で加工し、テーブルに表示しています。

```javascript
const onClickLoad = async () => {
    try {
        // 'records' コレクションから最大10件のドキュメントを取得するクエリを実行
        const querySnapshot = await getDocs(query(collection(db, "records"), limit(10)));

        // 取得したドキュメントのデータを処理して新しい配列を作成
        records = querySnapshot.docs.map(doc => {
            const data = doc.data();
            return {
                id: doc.id,
                data: {
                    date: data.date,   // 特定のフィールドを取得
                    item: data.item,
                    price: data.price
                }
            };
        });

        // テーブルの中身を空にする
        const tableBody = document.getElementById("data_table").tBodies[0];
        tableBody.innerHTML = '';
        
        // recordsに入っているデータをテーブルに追加
        records.forEach(doc => renderTableRow(doc.data));
    } catch (error) {
        alert("データの読み込みに失敗しました。エラーコード: " + error);
    }
};
```
