firestore> =未返回预期的结果

时间:2020-03-28 05:39:15

标签: firebase google-cloud-firestore

我再次使用>=查询集合。为了测试脚本,我的收藏集中只有4个条目。

我的查询是:

 ...
.where("Workdesc", ">=", "imple") // no returning as expected
.get()
.then(querySnapshot => {
    querySnapshot.forEach(function(doc) {
        console.log("Result");
        console.log(doc.id, " ===> ", doc.data());
    });
  });
所有4个文档中的

Workdesc是-

  • “ kj实现”
  • “紧急执行HB”
  • “需要实施sharu快速响应”
  • “ cb实施紧急工作”

根据我的结果,它应该已经返回了所有4个文档,但是仅返回了2个。我要附加控制台日志和Firebase控制台的屏幕截图:

enter image description here

enter image description here

如何在字符串中的任意位置获取带有部分字母的结果。

3 个答案:

答案 0 :(得分:0)

您的查询正在按预期方式工作。当您对字符串进行比较时,它们将按字典顺序或换句话说按字母顺序排序。这是每个值的实际排序顺序,其中“ impl”在其中排序:

  1. “ cb实施紧急工作”
  2. “紧急执行HB”
  3. “ Impl”
  4. “ kj实现”
  5. “需要实施sharu快速响应”

按字母顺序,您可以看到“ k”和“ s”在“ i”之后。因此,这些是您将从查询中获得的唯一文档,这些文档的Workdesc值大于“ impl”。

如果您尝试进行子字符串搜索以查找所有包含“ impl”的Workdesc字符串,则Firestore无法实现。 Firestore doesn't offer substring searches.您将不得不找到另一种方式(可能将数据镜像到支持它的另一个数据库)。

答案 1 :(得分:0)

不幸的是,要基于Doug的答案,Firestore不支持您要执行的字符串搜索类型。消除文本搜索的一种潜在解决方案是,您可以在待办事项文档上创建另一个字段,用于存储是否在处理“实现”。

例如,如果您有一个字段isImplementation(对于实现的待办事项将为true,而对于没有实现的则为false),则可以将此字段作为where子句的一部分添加到查询中。这样可以确保您仅获取实施待办事项。

答案 2 :(得分:0)

Firestore再一次建立在@Doug's answer上,便是一个具有索引的文档数据库。要查询数据,必须在一次扫描中针对索引执行查询,以保持查询在设计数据库时的性能。

Firebase默认情况下不会索引字符串字段,因为它效率不高并且在规模上相当繁琐。最好使用另一种方法。

例如,下面的函数将输入字符串分割为可搜索的部分,然后将其添加到索引中。随着输入字符串长度的增加,包含在其中的子字符串的数量迅速增加。

function shatter(str, minLength = 1) {
    let parts = [str]; // always have full string
    let i, subLength = minLength;
    let strLength = str.length;
    while (subLength < strLength) {
        for (i = 0; i < (strLength - subLength + 1); i++) {
            parts.push(str.substring(i, i + subLength));
        }
        subLength++;
    }
    return parts;
}

这是一个演示此内容的交互式代码段:

function shatter(str, minLength = 1) {
    let parts = [str]; // always have full string
    let i, subLength = minLength;
    let strLength = str.length;
    while (subLength < strLength) {
        for (i = 0; i < (strLength - subLength + 1); i++) {
            parts.push(str.substring(i, i + subLength));
        }
        subLength++;
    }
    return parts;
}

let str = prompt('Please type out a string to shatter:', 'This is a test string');
let partsOfMin1 = shatter(str, 1);
console.log('Shattering into pieces of minimum length 1 gives:', partsOfMin1);
let partsOfMin3 = shatter(str, 3);
console.log('Shattering into pieces of minimum length 3 gives:', partsOfMin3);
let partsOfMin5 = shatter(str, 5);
console.log('Shattering into pieces of minimum length 5 gives:', partsOfMin5);
alert('The string "' + str + '" can be shattered into as many as ' + partsOfMin1.length + ' pieces.\r\n\r\nThis can be reduced to only ' + partsOfMin3.length + ' with a minimum length of 3 or ' + partsOfMin5.length + ' with a minimum length of 5.');

无论如何使用上面的函数,我们都可以重新利用它,以便将破碎的片段保存到/substringIndex/todos/workDesc的Firestore中,并提供指向包含字符串的文档的链接。

const firebase = require('firebase');
firebase.initializeApp(/* config here */);

const arrayUnion = firebase.firestore.FieldValue.arrayUnion;
const TODOS_COL_REF = firebase.firestore().collection('todos');
const SUBSTRING_INDEX_COL_REF = firebase.firestore().collection('substringIndex');

// splits given string into segments ranging from the given minimum length up to the full length
function shatter(str, minLength = 1) {
    let parts = [str];
    let i, subLength = minLength;
    let strLength = str.length;
    while (subLength < strLength) {
        for (i = 0; i < (strLength - subLength + 1); i++) {
            parts.push(str.substring(i, i + subLength));
        }
        subLength++;
    }
    return parts;
}

// upload data
const testData = {
    workDesc: 'this is a prolonged string to break code',
    assignDate: firebase.firestore.Timestamp.fromDate(new Date()),
    assignTo: 'Ddy1QVOAO6SIvB8LfAE8Z0Adj4H3',
    followers: ['Ddy1QVOAO6SIvB8LfAE8Z0Adj4H3'],
    searchArray: ['v1', 'v2']
}

const todoDocRef = TODOS_COL_REF.doc();
const todoId = todoDocRef.id;
todoDocRef.set(testData)
    .then(() => console.log('Uploaded test data!'))
    .catch((err) => console.error('Failed to test data!', err));

// Note: in this example, I'm not waiting for the above promise to finish
// Normally, you would integrate it into the batched write operations below

// index each desired string field
const indexDocRef = SUBSTRING_INDEX_COL_REF.doc('todos');
const indexedFields = ["workDesc"];
const indexEntryMinLength = 3;

const indexUpdatePromises = indexedFields.map((fieldName) => {
    const indexColRef = indexDocRef.collection(fieldName);
    const fieldValue = testData[fieldName];
    if (typeof fieldValue !== 'string') return Promise.resolve(undefined); // skip non-string values

    const parts = shatter(fieldValue, indexEntryMinLength);

    console.log('INFO: Consuming ' + (parts.length * 2) + ' write operations to index ' + fieldName);

    // Each batched write can handle up to 500 operations, each arrayUnion counts as two
    const partsBatches = [];
    if (parts.length > 250) {
        for (let i = 0; i < parts.length; i += 250) {
            partsBatches.push(parts.slice(i, i + 250));
        }
    } else {
        partsBatches.push(parts);
    }

    const batchCommitPromises = partsBatches
        .map((partsInBatch) => {
            const batch = firebase.firestore().batch();
            partsInBatch.forEach((part) => {
                batch.set(indexColRef.doc(part), {ids: arrayUnion(todoId)}, { merge: true })
            })
            return batch.commit();
        });

    return Promise.all(batchCommitPromises);
})

Promise.all(indexUpdatePromises)
    .then(() => console.log('Uploaded substring index!'))
    .catch((err) => console.error('Failed to upload index!', err));

然后,当您要搜索包含"impl"的所有文档时,可以使用以下内容获取匹配的文档ID数组:

firebase.firestore().doc('substringIndex/todos/workDesc/impl').get()
  .then(snap => snap.get('ids'))
  .then(console.log, console.error)

尽管上面的代码有效,但是在更新索引时您将很快达到读/写限制,并且还可能会遇到并发问题。我还认为它很脆弱,因为非英语字符和标点符号也会使它崩溃-它仅作为演示提供。这些问题就是相关的Firebase documentation建议使用Algolia之类的第三方搜索服务进行全文搜索的原因。

TL:DR;

最好的解决方案是使数据"sharu implementation quick response needed"易于阅读,@Luis中{{3 }}。