【发布时间】:2019-05-08 03:55:20
【问题描述】:
我需要一次性将一张大型数据表导入我的数据库。我目前将其作为 Excel 文件保存,但我很乐意将其复制到 Google 表格等。
到目前为止,我已经直接通过 cloud firestore 手动添加了一些条目。
是否已经有解决方案来实现这一目标?
【问题讨论】:
我需要一次性将一张大型数据表导入我的数据库。我目前将其作为 Excel 文件保存,但我很乐意将其复制到 Google 表格等。
到目前为止,我已经直接通过 cloud firestore 手动添加了一些条目。
是否已经有解决方案来实现这一目标?
【问题讨论】:
我认为将表格数据导出到 Firestore 的最简单方法是使用 Google Apps 脚本库(用于 Google 表格)。
复制我作为示例创建的THIS example Google Spreadsheet
从步骤 1 中的示例 Google 电子表格副本的菜单中,单击 Tools > Script Editor。这应该会打开与示例电子表格关联的示例 Google App 脚本。
按照安装this library 的步骤操作,然后使用以下内容更新脚本:
这些变量是通过转到Google Service Accounts page 生成的。这将要求您已经有 Firebase 或 Google Cloud 帐户设置。我不会重复aforementioned Github writeup 中已经迭代的所有步骤。仔细跟随他们,并意识到 private_key 是整个密钥,以 -----BEGIN PRIVATE KEY-----\n 开头,介于两者之间,以 \n-----END PRIVATE KEY-----\n 结尾
在您的电子表格中插入一个包含您的数据的页面,然后编辑脚本以使用您的新工作表名称和数据。我已经对脚本进行了大量评论,因此几乎每一行代码都在做什么非常清楚。对于那些只想查看spreadsheet 背后的 Google 应用脚本的人,代码如下:
// Note this Script uses an external library as per this page:
// https://github.com/grahamearley/FirestoreGoogleAppsScript
// This solution requires a Google Spreadhseet and a Firebase Account
// FOLLOW THE INSTRUCTIONS ON THAT GITHUB REPO TO SETUP NEEDED API KEYS!!!
//Global Variables
const ss = SpreadsheetApp.getActiveSpreadsheet(); // Gets the active "workbook"
const sheet = ss.getSheetByName('Restaurants'); // CHANGE TO YOUR SHEET NAME
const headerRowNumber = 1; // If you have more than one row for your header, then change this value to number of header rows
// If you want to mark modified cells, then set up a trigger for the following function:
// Edit > Current Project Triggers > (+ Add Trigger) > On Edit Spreadsheet etc
function onEdit(e) {
var cell = ss.getActiveCell(); //This will also effectively get our row
var dataRange = sheet.getDataRange(); //This checks for all rows/columns with data
var modifiedCol = dataRange.getLastColumn()-1; //Our "modified" column should be the second to last
if (cell.getColumn() < modifiedCol && cell.getRow() > headerRowNumber) { //If we edit any cells to the left of our modified column and below our header...
var celltoMark = sheet.getRange(cell.getRowIndex(),modifiedCol) //Get the R/C cordinates of cell to place modified time
celltoMark.setValue(new Date()); //write timestamp to that cell
}
};
// This will parse any comma separated lists you create in any of your fields (useful for search words, or attributes, etc)
function listToArray(list) {
var ogArray = list.split(","); //Input is a comma separated list
let trimmedArr = ogArray.map(string => string.trim()); //Let's strip out the leading/trailing whitespaces if any
return trimmedArr; //return the cleaned array
}
function writeToFireStore() {
const email = 'sheets@yourprojectid.iam.gserviceaccount.com'; // CHANGE THIS!!!
const key = '-----BEGIN PRIVATE KEY-----\nYOURPRIVATEKEY\n-----END PRIVATE KEY-----\n'; // CHANGE THIS!!!
const projectID = 'yourprojectid'; // CHANGE THIS!!!
var firestore = FirestoreApp.getFirestore(email, key, projectID);
const collection = "MySpreadsheetData"; // Name of your Firestore Database "Collection"
var dataRange = sheet.getDataRange().offset(headerRowNumber, 0, sheet.getLastRow() - headerRowNumber); //this is your data range
var data = dataRange.getValues(); // this is an array of your datarange's values
var lastCol = dataRange.getLastColumn(); // this is the last column with a header
var newDoc = {}; // Instantiate your data object. Each one will become the data for your firestore documents
// r = row number in this case
for (let r = 0; r <= dataRange.getLastRow(); r++) {
//Logger.log("R = ",r);
var cellMod = dataRange.getCell(r+1, lastCol-1);
var cellFS = dataRange.getCell(r+1, lastCol);
var cellModVal = cellMod.getValue();
var cellFSVal = cellFS.getValue();
//
// IMPORTANT READ THIS IMPORTANT READ THIS IMPORTANT READ THIS IMPORTANT READ THIS IMPORTANT READ THIS!!!
// Well, read the line below...
if (r > 2) break; //Comment Out this line after you're done testing otherwise you'll write all your rows to firestore after every run
newDoc[r] = {
name : data[r][1],
category : data[r][2],
cuisine : data[r][3],
address: {
add1: data[r][4],
add2: data[r][5],
city: data[r][6],
state: data[r][7],
zip: data[r][8]
},
tel: data[r][9],
searchterms: listToArray(data[r][10]) //Let's turn a csv list into an array
}
// For the sake of efficiency and to save $, we WON'T create documents that have already been created...
// ...and we won't update documents that have a fireStore Timestamp that's newer than a Modified Timestamp
// If there's not firestore timestamp in our spreadsheet, then let's create firestore document and update firestore stamp:
if (!cellFSVal) {
var now = new Date(); //Generate timestamp right now
try {
firestore.createDocument(collection + "/" + data[r][0], newDoc[r]); // To Use Your Own Document ID
//Now let's insert a timestamp in our Firestore TS column of the sheet so we know it's been added to Firestore
cellFS.setValue(now);
Logger.log("Row ",r,"(",data[r][1],") is NEW and was added to FireStore Successfully");
} catch (e) {
Logger.log("Error: ",e," : Document with same name already existed in Firestore.");
}
}
//var if FS Timestamp exists but, the modified time stamp is greater, let's update the Firstore Document
else if ((cellFSVal) && (cellModVal > cellFSVal)) {
try {
firestore.updateDocument(collection + "/" + data[r][0], newDoc[r]);
//Now let's insert a timestamp in our Firestore TS column of the sheet so we know it's been updated to Firestore
cellFS.setValue(now);
Logger.log("Row ",r,"(",data[r][1],") updated/edited.");
} catch (e) {
Logger.log("Error: ",e," : Document existed, we tried updating it, but jack shit happened.");
}
}
else {
Logger.log("Row ",r,"(",data[r][1],") Already in Firestore & hasn't been modified. Skipped.");
}
}
}
根据您的需要修改脚本后,就可以运行该脚本了。只需保存它 (File > Save),然后从菜单栏中的“选择功能”下拉选择器中选择功能“writeToFireStore”(在错误图标之间)和灯泡),然后点击播放图标(在错误图标的左侧)。此时,可能会提示您接受运行脚本的权限(如果要运行脚本,您需要接受)。接受权限后,如果尚未运行“writeToFireStore”函数,请再次运行它,瞧!
我创建了一个函数,该函数自动将修改后的时间戳写入目标工作表中倒数第二列,当您运行该函数时,会写入一个 Firestore 时间戳(这样您就知道哪些行已成功导出到 Firestore)。这样,如果您再次运行 firestore 函数,并且您没有更改工作表上的数据,它就不会费心用相同的数据更新数据库(并且会为您节省金钱和/或服务器资源)。要使此功能正常工作,您必须设置项目触发器(在 cmets 的脚本中进行了说明)。
【讨论】: