我再次使用>=
查询集合。为了测试脚本,我的收藏集中只有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
是-
根据我的结果,它应该已经返回了所有4个文档,但是仅返回了2个。我要附加控制台日志和Firebase控制台的屏幕截图:
如何在字符串中的任意位置获取带有部分字母的结果。
答案 0 :(得分:0)
您的查询正在按预期方式工作。当您对字符串进行比较时,它们将按字典顺序或换句话说按字母顺序排序。这是每个值的实际排序顺序,其中“ impl”在其中排序:
按字母顺序,您可以看到“ 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之类的第三方搜索服务进行全文搜索的原因。
最好的解决方案是使数据"sharu implementation quick response needed"
易于阅读,@Luis中{{3 }}。