web-dev-qa-db-ja.com

CSVまたはJSONをFirebase Cloud Firestoreにインポートする方法

FirebaseリアルタイムデータベースのようにCSVまたはJSONをfirebaseクラウドfirestoreにインポートする方法はありますか?

enter image description here

42
Ted

一般的な解決策

JSONのアップロードを許可するスクリプトの多くのテイクを見つけましたが、サブコレクションを許可するものはありませんでした。上記の私のスクリプトは、あらゆるレベルのネストとサブコレクションを処理します。また、ドキュメントに独自のデータとサブコレクションがある場合も処理します。これは、コレクションがオブジェクトの配列/オブジェクト(空のオブジェクトまたは配列を含む)であるという仮定に基づいています。

スクリプトを実行するには、npmとノードがインストールされていることを確認してください。次に、コードをnode <name of the file>として実行します。クラウド機能として展開する必要はありません。

const admin = require('../functions/node_modules/firebase-admin');
const serviceAccount = require("./service-key.json");

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://<your-database-name>.firebaseio.com"
});

const data = require("./fakedb.json");

/**
 * Data is a collection if
 *  - it has a odd depth
 *  - contains only objects or contains no objects.
 */
function isCollection(data, path, depth) {
  if (
    typeof data != 'object' ||
    data == null ||
    data.length === 0 ||
    isEmpty(data)
  ) {
    return false;
  }

  for (const key in data) {
    if (typeof data[key] != 'object' || data[key] == null) {
      // If there is at least one non-object item in the data then it cannot be collection.
      return false;
    }
  }

  return true;
}

// Checks if object is empty.
function isEmpty(obj) {
  for(const key in obj) {
    if(obj.hasOwnProperty(key)) {
      return false;
    }
  }
  return true;
}

async function upload(data, path) {
  return await admin.firestore()
    .doc(path.join('/'))
    .set(data)
    .then(() => console.log(`Document ${path.join('/')} uploaded.`))
    .catch(() => console.error(`Could not write document ${path.join('/')}.`));
}

/**
 *
 */
async function resolve(data, path = []) {
  if (path.length > 0 && path.length % 2 == 0) {
    // Document's length of path is always even, however, one of keys can actually be a collection.

    // Copy an object.
    const documentData = Object.assign({}, data);

    for (const key in data) {
      // Resolve each collection and remove it from document data.
      if (isCollection(data[key], [...path, key])) {
        // Remove a collection from the document data.
        delete documentData[key];
        // Resolve a colleciton.
        resolve(data[key], [...path, key]);
      }
    }

    // If document is empty then it means it only consisted of collections.
    if (!isEmpty(documentData)) {
      // Upload a document free of collections.
      await upload(documentData, path);
    }
  } else {
    // Collection's length of is always odd.
    for (const key in data) {
      // Resolve each collection.
      await resolve(data[key], [...path, key]);
    }
  }
}

resolve(data);
48
Maciej Caputa

そのためにはカスタムスクリプトが必要です。

Firebaseライブラリ許可しないデータのインポートネストされた配列である限り、Firebase admin SDKに基づいて作成しました。

const admin = require('./node_modules/firebase-admin');
const serviceAccount = require("./service-key.json");

const data = require("./data.json");

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: "https://YOUR_DB.firebaseio.com"
});

data && Object.keys(data).forEach(key => {
    const nestedContent = data[key];

    if (typeof nestedContent === "object") {
        Object.keys(nestedContent).forEach(docTitle => {
            admin.firestore()
                .collection(key)
                .doc(docTitle)
                .set(nestedContent[docTitle])
                .then((res) => {
                    console.log("Document successfully written!");
                })
                .catch((error) => {
                    console.error("Error writing document: ", error);
                });
        });
    }
});

更新:このトピックに関する記事を書きました- Filling Firestore in data

16
Mikki

現時点では、独自のスクリプトを作成する必要はありません。

8
Dan McGrath

参考のため。 Firestoreでデータをインポートおよびエクスポートするのに役立つ関数を作成しました。

https://github.com/dalenguyen/firestore-import-export

6
Dale Nguyen

Maciej Caputaが提供するGeneral Solutionを使用しました。ありがとうございました (:

ここにいくつかのヒントがあります。 Ionic Firebaseアプリケーションが、そのソリューション内のfunctionsフォルダーに必要なFirebaseノードモジュールと共にインストールされていると仮定します。これは標準のIonic Firebaseインストールです。スクリプトとデータを同じレベルで保持するインポートフォルダーを作成しました。

フォルダ階層

myIonicApp
    functions
        node_modules
            firebase-admin
ImportFolder
    script.js
    FirebaseIonicTest-a1b2c3d4e5.json
    fileToImport.json

スクリプトパラメータ

const admin = require('../myIonicApp/functions/node_modules/firebase-admin'); //path to firebase-admin module
const serviceAccount = require("./FirebaseTest-xxxxxxxxxx.json"); //service account key file

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://fir-test-xxxxxx.firebaseio.com" //Your domain from the hosting tab
});

Domain name from the Hosting tab

サービスアカウントキーファイルの作成

  • プロジェクトのFirebaseコンソールで、Project Overwiewアイテムの横にある歯車アイコンをクリックし、[ユーザーと権限]を選択します
  • 画面の下部で、[アクセス許可の詳細設定]をクリックします

Accessing Google Cloud Platform Console

  • これにより、Google Cloud Platform Consoleの別のタブが開きます
  • 左側で[サービスアカウント]アイテムを選択します
  • 既存のサービスアカウントのサービスアカウントを作成する

App Engineのデフォルトサービスアカウントにキーを追加しただけです

キーの作成機能により、キーをJSONファイルにダウンロードできます

Creating the Service Account Key

JSONデータ構造

提供されているスクリプトを使用するには、データ構造が次のようになっている必要があります。

{
  "myCollection" : {
    "UniqueKey1" : {
      "field1" : "foo",
      "field2" : "bar"
    },{
    "UniqueKey2" : {
      "field1" : "fog",
      "field2" : "buzz"
    }...
}
6
pasx

https://Gist.github.com/JoeRoddy/1c706b77ca676bfc0983880f6e9aa8c8

これは、オブジェクトのオブジェクトに対して機能するはずです(一般的には、古いfirebase jsonのセットアップ方法)。 Firestoreで既に構成されているアプリにそのコードを追加できます。

正しいJSONファイルを指していることを確認してください。

がんばろう!

1
Joe Roddy

現時点ではできません。Firestoreはデータを異なる形式に構造化します。つまり、コレクションを使用し、各コレクションには一連のドキュメントがあり、JSON形式で保存されます。将来的にはJSONを変換するツールを作成する可能性があります参照してください。これを確認してください

https://cloud.google.com/firestore/docs/concepts/structure-data

****編集:****

プロセスをある程度まで自動化できます。つまり、CSVまたはJSONデータのフィールドのみをCloud Firestore DBにプッシュする模擬ソフトウェアを作成できます。データベース全体を移行し、DBを取得してFirestoreにプッシュする単純なアプリを作成しました

1
Anubhav Malik
var admin = require('firebase-admin');

var serviceAccount = require('./serviceAccountKey.json');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: 'https://csvread-d149c.firebaseio.com'
});

const csv = require('csv-parser');  
const fs = require('fs');

const firestore = admin.firestore();

// CSV FILE data.csv

// Name,Surname,Age,Gender
// John,Snow,26,M  
// Clair,White,33,F  
// Fancy,Brown,78,F

fs.createReadStream('data.csv')  
  .pipe(csv())
  .on('data', (row) => {
    console.log(row);
    if(row) {
      firestore.collection('csv').add({
        name: row.Name,
        surname: row.Surname,
        age: row.Age,
        sex: row.Gender
      });
    }
    else {
      console.log('No data')
    }
  })
  .on('end', () => {
    console.log('CSV file successfully processed');
  });
0
Atit Timilsina

これは、ドキュメントの「id」が存在する場合、そのパスにコピーする小さな変更です。それ以外の場合は、「for」のインデックスを使用します。

  ...
  ...
  } else {
    // Collection's length of is always odd.
    for (const key in data) {
      // Resolve each collection.
      if (data[key]['id']!==undefined)
        await resolve(data[key], [...path,data[key]['id']])
      else 
        await resolve(data[key], [...path, key]);
    }
  }
}

resolve(data);
0
rgrcnh

1-コレクションのみをインポートする

コレクションの名前が数字だけで構成されていない場合は、次のようにドキュメントの名前を定義できます。


    ...
    ...

    } else {
        // Collection's length of is always odd.
        for (const key in data) {
          // // Resolve each collection.

          // If key is a number it means that it is not a collection
          // The variable id in this case will be the name of the document field or you 
          // can generate randomly
          let id = !isNaN(key) ? data[key].id : key;

          await resolve(data[key], [...path, id]);
        }
      }
    }

2-コレクションとサブコレクションをインポートする

上記の例と同じように、サブコレクションの名前に数字のみを含めることはできません。

    ...
    ...

    for (const key in data) {
      // Resolve each collection and remove it from document data.
      if (isCollection(data[key], [...path, key])) {
        // Remove a collection from the document data.
        delete documentData[key];

        // If key is a number it means that it is not a collection
        // The variable id in this case will be the name of the document field or you 
        // can generate randomly
        let id = !isNaN(key) ? data[key].id : key;

        // Resolve a colleciton.
        resolve(data[key], [...path, id]);
      }
    }

    ...
    ...

注:@Maciej Caputaのコードの変更

0
Bruno Henrique