您可以创建动态 Firebase 查询吗?
我想像这样查询 firebase,但它不允许我这样做。有没有办法动态查询 firebase?我需要处理非常特殊的情况 - 例如,如果用户选择“无所谓”,那么我需要从查询中删除该首选项过滤器,一些字段是数组数据类型,一些是字符串,一些是数字。我需要能够处理所有形式的数据类型并适当地填充 where 子句。手动检查每个字段并调用每个字段将使系统负担过重(有超过 20 个字段需要查询)。任何建议都很好!
for(ddp in docDataPreferences){
if(docDataPreferences[ddp] == "Doesn't Matter"){
allDoesntMatterPreferences.push(ddp);
} else if(docDataPreferences[ddp] != "Doesn't Matter" && docDataPreferences[ddp] != '' && docDataPreferences[ddp] != undefined) {
keysWithValues.push(ddp);
whereClause += ".where('preferences."+ ddp + "', 'array-contains-any', " + JSON.stringify(docDataPreferences[ddp]) +")"
}
}
var usersMatchesCollection = config.db.collection("Users");
var query = usersMatchesCollection + whereClause;
await query.get().then( function (matchesQuerySnapshot) {
matchesQuerySnapshot.forEach(function(doc) {
//...do something
})
})
TypeError: query.get is not a function. (In 'query.get()', 'query.get' is undefined)]
我可以看到 where 子句打印正确,但我认为您无法连接对象和字符串。当我手动添加返回的 whereClause 时,如下所示:
var query = usersMatchesCollection.where('preferences.datingPrefDistance', '==', 22).where('preferences.datingPrefDrinking', '==', "No").where('preferences.datingPrefEducation', '==', "Doctorate").where('preferences.datingPrefKids', '==', "No").where('preferences.datingPrefMarried', '==', "No").where('preferences.datingPrefSmokingCig', '==', "No").where('preferences.datingPrefSmokingPot', '==', "No").where('preferences.prefDrinking', '==', "No").where('preferences.prefEducation', '==', "Doctorate").where('preferences.prefIdentifyAs', '==', "Male").where('preferences.prefKids', '==', "No").where('preferences.prefMarried', '==', "No").where('preferences.prefSmokingPot', '==', "No")
它有效。因此,是连接导致了问题。
有解决方法吗?
您似乎试图通过连接
CollectionReference
和字符串来构建查询,但这样做行不通。如果您
console.log(query)
,您将看到它是一个字符串,而不是
Query
,并且由于字符串上没有
get()
方法,这解释了您收到的错误。
要构建具有动态条件的查询,您应该遵循以下模式:
var usersMatchesCollection = config.db.collection("Users");
var query = usersMatchesCollection;
for(ddp in docDataPreferences){
if(docDataPreferences[ddp] == "Doesn't Matter"){
allDoesntMatterPreferences.push(ddp);
} else if(docDataPreferences[ddp] != "Doesn't Matter" && docDataPreferences[ddp] != '' && docDataPreferences[ddp] != undefined) {
keysWithValues.push(ddp);
query = query.where('preferences.'+ ddp, 'array-contains-any', docDataPreferences[ddp]))
}
}
await query.get().then( function (matchesQuerySnapshot) {
matchesQuerySnapshot.forEach(function(doc) {
//...do something
})
})
这里的关键是
query = query.where
不断变化,将查询替换为每个条件的另一个查询,并添加新条件。然后,处理完所有条件后,您可以执行最终查询。
我试图确保代码与您的代码匹配,但该行中可能存在一两个语法错误,因为我不得不猜测
docDataPreferences
包含什么。
Olivia,我经常使用 Frank 模式的变体 - 我传入一个数组,其中每个条目都是一个对象 {fieldref: string, opstr: string, value: value}。我的代码 .reduce 遍历数组,传递生成的扩展查询,如下所示:
/********************************************************
* @function collectRecordsByFilter returns an array of documents from Firestore
*
* @param table a properly formatted string representing the requested collection
* - always an ODD number of elements
* @param filterArray an array of argument object, each of the form:
* {
* fieldRef: string, // field name, or dotted field name
* opstr: string // operation string representation
* value: value // value for query operation
* }
* @param ref (optional) allows "table" parameter to reference a sub-collection
* of an existing document reference (I use a LOT of structered collections)
*
* The array is assumed to be sorted in the correct order -
* i.e. filterArray[0] is added first; filterArray[length-1] last
* returns data as an array of objects (not dissimilar to Redux State objects)
* with both the documentID and documentReference added as fields.
*/
export const collectRecordsByFilter = (table, filterArray, ref = null) => {
const db = ref ? ref : firebase.firestore();
//assumes filterArray is in processing order
let query = db.collection(table);
query = filterArray.reduce((accQuery, filter) => {
return accQuery.where(filter.fieldRef, filter.opStr, filter.value);
}, query);
return query
.get() //get the resulting filtered query results
.then(querySnapshot => {
return Promise.resolve(
querySnapshot.docs.map(doc => {
return {
...doc.data(),
Id: doc.id,
ref: doc.ref
};
})
);
})
.catch(err => {
return Promise.reject(err + ":collectRecordsByFilter");
});
};
关键是“query”不是一种方法,而是一个查询对象,它有一个方法“where”,可以有效地将新条件附加到查询对象 - 它不是覆盖,而是扩展。
使用中:
export const fetchTourByDateAndArtist = (dateString, artist) => {
//for each artist, only *one* tour bridges any particular data (except the default)
const filterArray = [
{ fieldRef: "dateStart", opStr: "<=", value: dateString }
];
return collectRecordsByFilter("Tours", filterArray, artist.ref).then(
tours => {
return Promise.resolve(
tours.find(tour => {
return moment(tour.dateEnd).isSameOrAfter(dateString);
})
);
}
);
};
这种方法为我抽象了 Firestore,并允许大量重复使用。
Tracy Hall (LeadDreamer)