以下是我想要实现的目标:我想每天从URL获取一个JSON,并将其转换为云火库集合,以便能够在我的Flutter应用程序中使用它。理想情况下,脚本只会向集合中添加新数据。
我发现我可以使用Firebase云函数中的scheduler
来每天运行任务。这不是现在的问题。
然而,我不知道如何正确使用Firebase云函数从URL中获取数据并将其转换为集合。也许这不是云功能的重点,我误解了一些东西。所以第一个问题:我可以在云函数中运行经典的nodeJS吗?我想我可以
接下来,我在本地初始化了一个云功能项目,将其连接到我的Google帐户,并开始将代码写入index.js
。
const functions = require("firebase-functions");
const admin = require('firebase-admin');
const fetch = require('node-fetch');
const db = admin.firestore();
const collectionToiletRef = db.collection('mycollection');
let settings = { method: "Get" };
let url = "my-url.com"
fetch(url, settings)
.then(res => res.json())
.then((json) => {
print(json);
// TODO for each json object, add new document
});
第二个问题:如何运行此代码以查看它是否有效我看到可以使用模拟器,但我如何才能直观地检查我的云火库集合?在这个简单的例子中,我只想打印json,看看我是否可以正确地获得数据。印刷在哪里进行?
也许云功能不是我完成这项任务所需要的。也许我的代码不好。我不知道。谢谢你的帮助。
编辑
我试过了,但电话一直没断。我认为这是在等待一个永不回报的承诺或类似的事情。
const functions = require("firebase-functions");
const admin = require('firebase-admin');
const fetch = require('node-fetch');
admin.initializeApp();
const db = admin.firestore();
exports.tempoCF = functions
.firestore.document('/tempo/{docId}')
.onCreate(async (snap, context) => {
console.log("onCreate");
let settings = { method: "Get" };
let url = "https://opendata.paris.fr/api/records/1.0/search/?dataset=sanisettesparis&q=&rows=-1"
try {
let response = await fetch(url, settings);
let json = await response.json();
// TODO for each json object, add new document
await Promise.all(json["records"].map(toiletJsonObject => {
return db.collection('toilets').doc(toiletJsonObject["recordid"]).set({}); // Only to create documents, I will deal with the content later
}));
}
catch(error) {
console.log(error);
return null;
}
}
);
这段代码可以工作并创建我想要的所有文档,但永远不会返回。然而,传递给onCreate
的async (snap, context) => {}
是一个Promise。当Promise.all
结束时,这个承诺就结束了。我错过了一些东西,但我不知道为什么。我在使用Dart或JS进行异步编程时遇到了很多困难。我心里不是很清楚。
我可以在云函数中运行经典的nodeJS吗?
当然!由于fetch方法返回Promise,因此您可以很好地在后台触发或调度的Cloud Function中使用它。
如何运行此代码以查看它是否有效?
您的代码将在模拟器套件中完美工作,但您需要使用可以在模拟器中运行的Firebase服务之一触发云功能。例如,您可以通过在Firestore模拟器控制台中创建文档来触发云函数。
下面的Cloud函数可以做到这一点:只需在伪tempo
集合中创建一个文档,CF就会在newDocs
集合中添加一个新文档。这取决于您为这个文档调整字段值,我刚刚使用了整个JSON对象。
exports.tempoCF = functions
.firestore.document('/tempo/{docId}')
.onCreate((snap, context) => {
let settings = { method: "Get" };
let url = "https://..."
return fetch(url, settings)
.then(res => res.json())
.then((json) => {
console.log(json);
// TODO for each json object, add new document
return admin.firestore().collection('newDocs').add(json);
})
.catch(error => {
console.log(error);
return null;
});
});
您也可以将云功能部署到Firebase后端,如果您想安排它,只需按如下方式更改代码(更改触发器(:
exports.scheduledFunction = functions.pubsub.schedule('every 5 minutes').onRun((context) => {
let settings = { method: "Get" };
let url = "https://..."
return fetch(url, settings)
.then(res => res.json())
.then((json) => {
console.log(json);
// TODO for each json object, add new document
return admin.firestore().collection('newDocs').add(json);
})
.catch(error => {
console.log(error);
return null;
});
});
编辑后进行编辑:
以下代码在模拟器中正常工作,在toilets
集合中创建文档。
exports.tempoCF = functions.firestore
.document('/tempo/{docId}')
.onCreate(async (snap, context) => {
console.log('onCreate');
let settings = { method: 'Get' };
let url =
'https://opendata.paris.fr/api/records/1.0/search/?dataset=sanisettesparis&q=&rows=-1';
try {
let response = await fetch(url, settings);
let json = await response.json();
return Promise.all( // Here we return the promise returned by Promise.all(), so the life cycle of the CF is correctly managed
json['records'].map((toiletJsonObject) => {
admin
.firestore()
.collection('toilets')
.doc(toiletJsonObject['recordid'])
.set({ adresse: toiletJsonObject.fields.adresse });
})
);
} catch (error) {
console.log(error);
return null;
}
});