# #node.js #firebase #google-cloud-functions
Вопрос:
Вот чего я хочу добиться : я хочу ежедневно получать JSON с URL-адреса и конвертировать его в коллекцию облачных магазинов firestore, чтобы иметь возможность использовать его в своем приложении Flutter. В идеале сценарий будет добавлять только новые данные в коллекцию.
Я увидел, что могу использовать scheduler
облачные функции Firebase для ежедневного выполнения задач. Сейчас это не проблема.
Однако я не знаю, как правильно использовать облачные функции 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
});
Второй вопрос : Как я могу запустить этот код, чтобы проверить, работает ли он ? Я видел, что эмулятор можно использовать, но как я могу визуально проверить свою коллекцию cloud firestore ? В этом простом примере я хочу распечатать свой 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=sanisettesparisamp;q=amp;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;
}
}
);
Этот код работает и создает все документы, которые я хочу, но никогда не возвращаю. Однако async (snap, context) => {}
переданное onCreate
-это Обещание. И это обещание заканчивается, когда Promise.all
заканчивается. Я что-то упускаю, но не знаю почему. Я много борюсь с асинхронным программированием с помощью Dart или JS. Не очень ясно у меня в голове.
Ответ №1:
Могу ли я запускать классические функции NodeJS внутри облачных функций?
Конечно! Поскольку метод выборки возвращает обещание, вы можете очень хорошо использовать его в фоновом режиме или в запланированной облачной функции.
Как я могу запустить этот код, чтобы проверить, работает ли он?
Ваш код будет отлично работать в наборе эмуляторов, но вам нужно будет запустить облачную функцию с помощью одной из служб Firebase, которые могут запускаться в эмуляторе. Например, вы можете запустить облачную функцию, создав документ в консоли эмулятора Firestore.
Следующая облачная функция сделает свое дело: просто создайте документ в фиктивной 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=sanisettesparisamp;q=amp;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;
}
});
Комментарии:
1. Тх, я попробую это сделать ! Но зачем мне нужно инкапсулировать код в CF ? Нет никакого способа запустить функцию NodeJS за пределами CF ? Кроме того, я думал, что все
export
дело в том, чтобы создать конечную точку, которую можно вызвать с помощью http-запроса. Будет ли экспортированная функция запускаться автоматически при выполнении файла JS в эмуляторе ? Наконец, есть ли способ создать что-то вроде фабрики из JSON, которая только добавляет новые записи в Firestore, или мне нужно сделать это вручную ?2. Мне удалось заставить эмулятор работать, спасибо. Однако, когда я запускаю эмулятор, он запускает
index.js
и, я полагаю, создает конечную точку для tempoCF, но эта функция не вызывается. Как я могу запустить его вручную перед тестированием запланированной функции ? Я должен позвонить что-то вроде localhost:5001/tempoCF ?3. «нужно ли мне инкапсулировать код в CF» => Да, см. > firebase.google.com/docs/reference/functions/cloud_functions_ . Есть ли способ создать что-то вроде фабрики из JSON => Вы можете использовать любой код JavaScript/машинописи или библиотеку для создания объектов, которые вы используете для создания документов Firestore.
4. «Как я могу запустить его вручную перед тестированием запланированной функции ?» => Я привел пример с триггером Firestore в своем ответе (>
tempo
коллекция). Вы можете запустить его в эмуляторе как функцию HTTP , но поскольку вы собираетесь развернуть его как запланированную функцию, я бы рекомендовал использовать фоновый триггер, так как код будет таким же, как и для запланированной функции.5. Спасибо за ответы! Я отредактировал свой код, так как есть кое-что, чего я не понимаю в асинхронных функциях, если вы не возражаете, взгляните на это.