我需要一次将大数据表导入数据库。我目前将其保存为Excel文件,但很高兴将其复制到Google表格等中。
到目前为止,我已经直接通过Cloud Firestore手动添加了一些条目。
是否已经有解决方案来实现这一目标?
答案 0 :(得分:1)
我认为将表数据导出到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 App脚本的人,以下是代码:
// 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”功能,瞧!
我创建了一个函数,该函数自动将Modified Timestamp写入目标表的倒数第二列,并且在您运行该函数时,编写一个Firestore时间戳(这样您就可以知道哪些行已成功导出到Firestore)。这样,如果您再次运行firestore函数,并且没有更改工作表上的数据,它将不会费心用相同的数据更新数据库(这将节省金钱和/或服务器资源)。为了使用此功能,您必须设置项目触发器(在脚本的注释中对其进行了解释)。