【问题标题】:How to import CSV or JSON to firebase cloud firestore如何将 CSV 或 JSON 导入到 Firebase Cloud Firestore
【发布时间】:2018-03-20 08:10:11
【问题描述】:

有没有办法像在 firebase 实时数据库中一样将 CSV 或 JSON 导入到 firebase cloud firestore?

【问题讨论】:

  • 查看我的帖子以获得一般解决方案,也可以处理子集合。

标签: firebase google-cloud-firestore


【解决方案1】:

没有,此时您需要编写自己的脚本。

【讨论】:

  • 您有关于如何编写脚本的链接吗,谢谢!
  • 我喜欢 Firebase 如何在 stackoverflow 上竭尽全力以了解开发人员需要什么,但如果这些努力最终导致添加功能,那就太好了。我会说 JSON/CSV 上传会很棒:)
【解决方案2】:

到目前为止,您不能……firestore 将数据构造成不同的格式,即使用集合,每个集合都有一系列文档,然后以 JSON 格式存储……将来他们可能会成为一个工具将 JSON 转换为 firestore.. 以供参考,请查看

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

****编辑:****

您可以在一定程度上自动化该过程,即编写一个模拟软件,仅将 CSV 或 JSON 数据的字段推送到 Cloud Firestore 数据库中。我迁移了整个数据库,只制作了一个简单的应用程序,该应用程序检索了我的数据库并将其推送到 Firestore

【讨论】:

    【解决方案3】:

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

    这应该适用于对象的对象(通常设置了多少旧的 firebase json)。您可以将该代码添加到已配置 Firestore 的应用中。

    只要确保它指向正确的 JSON 文件即可。

    祝你好运!

    【讨论】:

      【解决方案4】:

      您需要一个自定义脚本来执行此操作。

      我基于 Firebase admin SDK 编写了一个,只要 firebase 库不允许您导入 嵌套数组的数据。

      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 with data

      【讨论】:

      • 底部的链接非常有帮助,并且提供了很多上下文,这使得这个答案更有意义。
      • 感谢您的示例和文章。这个解决方案对我来说非常有效,并帮助解释了如何在后端做一些 Vue.js 新手非常欣赏的事情!
      • 这看起来很有希望
      • 您使用此页面上的任何这些节点脚本制作的文章对我来说都是可能的。在 Firebase 中设置该服务至关重要。
      • 工作就像一个魅力
      【解决方案5】:

      一般解决方案

      我发现许多脚本允许上传 JSON,但没有一个允许子集合。我上面的脚本处理任何级别的嵌套和子集合。它还处理文档有自己的数据和子集合的情况。这是基于集合是对象的数组/对象(包括空对象或数组)的假设。

      要运行脚本,请确保您已安装 npm 和 node。然后以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);
      

      【讨论】:

      • 这对我来说非常有用,这是一个比 Mikki 更好(强大且通用)的解决方案。使用这个——顺便说一句,设置是一样的,所以你可以很容易地尝试这个或 Mikki 的那个——只需替换实际代码。
      • @Maciej Caputa,您的解决方案效果很好。谢谢。但是,您能否建议如何修改 fakedb.json 以使其生成自动 Id,而不是序列 - 1、2、3、...
      • 很高兴为您提供帮助。我在答案中添加了注释以供进一步参考。
      • 如果您还可以提供 JSON 结构的示例以用于为数据库提供数据,那就太好了。我运行了脚本,它为每个数据块创建了一个单独的集合,并且字段中的每个字符都作为一个单独的字段出现。现在我有一个大烂摊子要清理,没有批量删除功能......
      • 这里是一个子集合的例子: { "testCollection": { "testDocument": { "testNestedCollection": { "testNestedDocument": { "nestedName": "Jack" } }, "name": “约翰” } } }。在使用脚本之前,您应该使用 JSON linter,例如 jsonlint.com,以确保您的语法正确。
      【解决方案6】:

      供参考。我写了一个函数来帮助在 Firestore 中导入和导出数据。

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

      【讨论】:

      • 简单易行。谢谢
      • 伙计,这里的其他解决方案被低估了。谢谢!!
      【解决方案7】:

      我使用了 Maciej Caputa 提供的通用解决方案。谢谢(:

      这里有一些提示。假设您在该解决方案的 functions 文件夹中安装了 Ionic Firebase 应用程序,其中包含所需的 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
      });
      

      创建服务帐户密钥文件

      • 在您项目的 Firebase 控制台中,项目旁边 浏览项目,单击齿轮图标并选择用户和 权限
      • 在屏幕底部,单击高级权限 设置

      • 这会打开 Google Cloud Platform Console 的另一个选项卡
      • 在左侧选择服务帐户项
      • 为现有服务帐户创建服务帐户

      我只是为 App Engine 默认服务帐户添加了一个密钥

      创建密钥功能将提供将密钥下载到 JSON 文件的功能

      JSON 数据结构

      要使用提供的脚本,数据结构必须如下:

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

      【讨论】:

      • 这篇文章和 Mikki 的文章帮助我让 Maciej 的脚本正常工作。如果 Maciej 在他的回答中将所有内容放在一起,这对后代来说会很好。此处的示例 JSON 中有一个错误,尽管没有它,我遇到了数组行为与我预期不同的问题。错误出现在类似于 },{ 的行中。除非我们尝试创建子集合,否则额外的 { 需要消失。
      【解决方案8】:

      这是一个小的修改,将文档的“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);
      

      【讨论】:

        【解决方案9】:

        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 代码的更改

        【讨论】:

          【解决方案10】:
          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');
            });
          

          【讨论】:

          • 你应该解释你的代码你写了什么。
          【解决方案11】:

          Python 中的这种解决方法可能对某些人有所帮助。首先使用 Pandas 将 json 或 csv 转换为 dataframe,然后将 dataframe 转换为字典并将字典上传到 firestore。

          import firebase_admin as fb
          from firebase_admin import firestore
          import pandas as pd
          
          cred = fb.credentials.Certificate('my_credentials_certificate.json')
          default_app = fb.initialize_app(cred)
          db = firestore.client()
          
          df = pd.read_csv('data.csv')
          dict = df.to_dict(orient='records')
          
          my_doc_ref = db.collection('my_collection').document('my_document')
          my_doc_ref.set(dict)
          

          在使用类似于 Pandas 的库的 javascript 和其他语言中可能存在类似的解决方法。

          【讨论】:

            猜你喜欢
            • 2020-06-02
            • 2018-08-11
            • 1970-01-01
            • 2020-01-18
            • 2021-03-31
            • 2021-04-18
            • 2022-01-23
            相关资源
            最近更新 更多