使用 Firestore Cloud Function 将所有记录导出到 Algolia 索引

export all records to Algolia index with Firestore Cloud Function

我坚持使用 Firestore Cloud Function 获取所有现有文档并在 Algolia 中为它们编制索引的语法。我真的只想做一次,但如果能理解如何做就太好了。

我在 index.js 顶部的配置是:

    "use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateCustomerReportLink = exports.createUser = exports.helloWorld = void 0;

const functions = require("firebase-functions");
const admin = require("firebase-admin");
const algoliasearch = require('algoliasearch')

admin.initializeApp();

const actionCodeSettings = {
    // URL you want to redirect back to. The domain (www.example.com) for
    // this URL must be whitelisted in the Firebase Console.
    url: 'https://www.myurl.com',
    // This must be true for email link sign-in.
    handleCodeInApp: true,
};

const ALGOLIA_ID = functions.config().algolia.app;
const ALGOLIA_ADMIN_KEY = functions.config().algolia.api_key;
// const ALGOLIA_SEARCH_KEY = functions.config().algolia.search_key;

const client = algoliasearch(ALGOLIA_ID, ALGOLIA_ADMIN_KEY);
const ALGOLIA_INDEX_NAME = 'Sessions';
const index = client.initIndex(ALGOLIA_INDEX_NAME);

我能找到的所有文档要么不使用云函数,要么像这些示例中那样使用像 onWrite 这样的云函数触发器 cloud function examples

看起来像语法

exports.indexentry = functions.database.ref('/blog-posts/{blogid}/text').onWrite(

只适用于触发方式?

我目前已设置并运行函数,并且我的 algolia 配置已正确设置,因为我有一个由 onCreate 触发的云函数,它在 algolia 中创建了一个新索引并且效果很好。

我尝试编写的函数代码是这样的:

const ALGOLIA_ID = functions.config().algolia.app;
const ALGOLIA_ADMIN_KEY = functions.config().algolia.api_key;
// const ALGOLIA_SEARCH_KEY = functions.config().algolia.search_key;

const client = algoliasearch(ALGOLIA_ID, ALGOLIA_ADMIN_KEY);
const ALGOLIA_INDEX_NAME = 'Sessions';
const index = client.initIndex(ALGOLIA_INDEX_NAME);


const _collection = admin.firestore().collection('sessions');

exports.sendCollectionToAlgolia = functions._collection.once('value', sessions => {
// Build an array of all records to push to Algolia
const records = [];
sessions.forEach(session => {
  // get the key and data from the snapshot
  const childKey = session.key;
  const childData = session;
  // We set the Algolia objectID as the Firebase .key
  childData.objectID = childKey;
  // Add object for indexing
  records.push({
        sessionDate: childData.sessionDate,
        customer1FirstName: childData.customer1FirstName,
        customer1LastName: childData.customer1LastName
    }); 
});

// Add or update new objects
index
  .saveObjects(records)
  .then(() => {
    console.log('Contacts imported into Algolia');
  })
  .catch(error => {
    console.error('Error when importing contact into Algolia', error);
    process.exit(1);
  });

});

但是我在部署时遇到错误:

TypeError: Cannot read property 'database' of undefined

如果我将此代码用于我的云函数,它基于此处的代码示例 algolia docs firestore examples 函数部署,但是当我在浏览器中调用测试函数 url 时,我得到 408并且请求超时。

exports.sendCollectionToAlgolia = functions.https.onRequest(async (req, res) => {

    // This array will contain all records to be indexed in Algolia.
    // A record does not need to necessarily contain all properties of the Firestore document,
    // only the relevant ones. 
    const algoliaRecords = [];

    // Retrieve all documents from the COLLECTION collection.
    const querySnapshot = await admin.firestore().collection('Sessions').get();

    querySnapshot.docs.forEach(doc => {
        const document = doc.data();
        // Essentially, you want your records to contain any information that facilitates search, 
        // display, filtering, or relevance. Otherwise, you can leave it out.
        const record = {
            objectID: doc.id,
            sessionDate: document.sessionDate,
            customer1FirstName: document.customer1FirstName,
            customer1LastName: document.customer1LastName
        };

        algoliaRecords.push(record);
    });
    
    // After all records are created, we save them to 
    index.saveObjects(algoliaRecords, (_error, content) => {
        res.status(200).send("COLLECTION was indexed to Algolia successfully.");
    });
    
})

对于:

TypeError: Cannot read property 'database' of undefined

您正在使用实时数据库语法。对于 Firestore 它将是:

exports.indexentry = functions.firestore.document('/blog-posts/{blogid}/text').onWrite(

相关文档是 here

我有一些错误。大多数错误原来是一个简单的 js 错误,其中传递给 saveObjects() 函数的列表的长度始终为 0,因此我更改了列表的范围并将其链接到承诺中 then:

const runtimeOpts = {
    timeoutSeconds: 540,
    memory: '1GB'
  }

// Get all sessions from Firebase
exports.sendCollectionToAlgolia = functions.runWith(runtimeOpts).https.onRequest(async (req, res) => {

admin.firestore().collection("sessions").get().then((docs) => {

    let _sessions = [];

    docs.forEach((doc) => {

        let session = doc.data();

        const childKey = doc.id;

        if (
            session.customerInfo.customers.customer1.customerFirstName && 
            session.customerInfo.customers.customer1.customerLastName
        ) {
            const childData = {
                indexData: {
                    sessionDate: session.sessionDate,
                    customer1FirstName: session.customerInfo.customers.customer1.customerFirstName,
                    customer1LastName: session.customerInfo.customers.customer1.customerLastName,
                }
            }

            childData.objectID = childKey;
            _sessions.push(childData);
        }
    })
    return _sessions;
}).then((_sessions) => {

    index.saveObjects(_sessions)
    .then(() => {
      console.log('Contacts imported into Algolia');
    })
    .catch(error => {
      console.error('Error when importing contact into Algolia', error);
      process.exit(1);
    });
})

});

附带说明 - 记录整个文档字段数组仅在文档非常小的情况下才有效。在云函数控制台中记录任何内容的全部输出是个坏主意!