一般的な解決策
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);
そのためにはカスタムスクリプトが必要です。
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
現時点では、独自のスクリプトを作成する必要はありません。
参考のため。 Firestoreでデータをインポートおよびエクスポートするのに役立つ関数を作成しました。
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
});
サービスアカウントキーファイルの作成
App Engineのデフォルトサービスアカウントにキーを追加しただけです
キーの作成機能により、キーをJSONファイルにダウンロードできます
JSONデータ構造
提供されているスクリプトを使用するには、データ構造が次のようになっている必要があります。
{
"myCollection" : {
"UniqueKey1" : {
"field1" : "foo",
"field2" : "bar"
},{
"UniqueKey2" : {
"field1" : "fog",
"field2" : "buzz"
}...
}
https://Gist.github.com/JoeRoddy/1c706b77ca676bfc0983880f6e9aa8c8
これは、オブジェクトのオブジェクトに対して機能するはずです(一般的には、古いfirebase jsonのセットアップ方法)。 Firestoreで既に構成されているアプリにそのコードを追加できます。
正しいJSONファイルを指していることを確認してください。
がんばろう!
現時点ではできません。Firestoreはデータを異なる形式に構造化します。つまり、コレクションを使用し、各コレクションには一連のドキュメントがあり、JSON形式で保存されます。将来的にはJSONを変換するツールを作成する可能性があります参照してください。これを確認してください
: https://cloud.google.com/firestore/docs/concepts/structure-data
****編集:****
プロセスをある程度まで自動化できます。つまり、CSVまたはJSONデータのフィールドのみをCloud Firestore DBにプッシュする模擬ソフトウェアを作成できます。データベース全体を移行し、DBを取得してFirestoreにプッシュする単純なアプリを作成しました
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');
});
これは、ドキュメントの「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);
コレクションの名前が数字だけで構成されていない場合は、次のようにドキュメントの名前を定義できます。
...
...
} 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]);
}
}
}
上記の例と同じように、サブコレクションの名前に数字のみを含めることはできません。
...
...
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のコードの変更