Firebase Cloud Firestore에 특정 필드가 존재하거나 존재하지 않는 문서를 가져오려면 어떻게 해야 합니까?
Firebase Cloud Firestore에서 컬렉션에 "user_gals"가 있으며 목표는 미리 정의된 목표(master_id: "XXXX") 또는 사용자 지정 목표("master_id" 키 없음)일 수 있습니다.
자바스크립트에서 저는 두 가지 기능을 작성해야 하는데, 하나는 미리 정의된 모든 목표를 얻기 위한 것이고 다른 하나는 모든 사용자 정의 목표를 얻기 위한 것입니다.
"master_id"를 "" 빈 문자열"로 설정하여 사용자 지정 목표를 얻기 위한 몇 가지 해결 방법을 찾았고 다음과 같이 얻을 수 있습니다.
db.collection('user_goals')
.where('challenge_id', '==', '') // workaround works
.get()
여전히 이것은 올바른 방법이 아닙니다. 저는 아래와 같이 "master_id"가 있는 미리 정의된 목표에 대해 계속 사용했습니다.
db.collection('user_goals')
.where('challenge_id', '<', '') // this workaround
.where('challenge_id', '>', '') // is not working
.get()
Firestore에 "가 없기 때문입니다!연산자, 저는 "<"과 ">" 연산자를 사용해야 하지만 여전히 성공하지 못했습니다.
질문:.이러한 해결 방법을 무시하고 특정 필드가 있는지 여부를 확인하여 문서를 가져오는 데 선호되는 방법은 무엇입니까?
@Emile Moureau 솔루션처럼.선호합니다
.orderBy(`field`)
필드를 사용하여 문서를 쿼리할 수 있습니다.데이터 유형에 상관없이 사용할 수 있으며, 데이터 유형에서 작동하기 때문입니다.null
.
하지만 @Doug Stevenson이 말했듯이:
Firestore에 없는 항목은 쿼리할 수 없습니다.Firestore 인덱스가 필드를 인식하려면 필드가 있어야 합니다.
필드가 없으면 문서를 쿼리할 수 없습니다.적어도 지금은.
지정된 필드가 있는 곳에서 문서를 가져오는 일반적인 방법은 다음과 같습니다.
.orderBy(fieldPath)
Firebase 설명서에 지정된 대로:
따라서 @hisoft가 제공한 답변은 유효합니다.저는 단지 선호하는 방법에 대한 질문이었기 때문에 공식적인 출처를 제공하기로 결정했습니다.
Firestore는 인덱스된 데이터베이스입니다.문서의 각 필드에 대해 해당 문서는 환경설정에 따라 해당 필드의 색인에 삽입됩니다.문서에 특정 필드가 없는 경우(예:challenge_id
해당 필드의 인덱스에 나타나지 않으며 해당 필드의 쿼리에서 생략됩니다.일반적으로 Firestore의 설계 방식 때문에 쿼리는 한 번의 연속 스위프에서 인덱스를 읽어야 합니다.의 도입 전에!=
그리고.not-in
즉, 인덱스 섹션을 건너뛰어야 하므로 특정 값을 제외할 수 없습니다.은 배타적범위를 하려고 할 때 합니다.v<2 || v>4
됩니다.를 단일 쿼리로 표시합니다.
필드 값은 실시간 데이터베이스 정렬 순서에 따라 정렬됩니다. 단, 문서의 ID 대신 중복이 발생할 때 여러 필드로 결과를 정렬할 수 있습니다.
Firestore 값 정렬 순서
우선 순위. | 정렬된 값 | 우선 순위. | 정렬된 값 |
---|---|---|---|
1 | null |
6 | 줄들 |
2 | false |
7 | 문서 참조 |
3 | true |
8 | 지오포인트 |
4 | 숫자들 | 9 | 배열 |
5 | 타임스탬프 | 10 | 지도 |
!=
/<>
이 섹션은 릴리스 이전에 불평등이 어떻게 작동했는지 문서화합니다.!=
그리고.not-in
2020년 9월에 운영자.이러한 연산자의 사용 방법에 대한 설명서를 참조하십시오.다음 섹션은 역사적인 목적을 위해 남겨질 것입니다.
Firestore에서 부등식 쿼리를 수행하려면 Firestore의 인덱스를 읽어 쿼리를 읽을 수 있도록 쿼리를 다시 작성해야 합니다.됩니다. 는 " 를▁the▁less▁than▁for▁-▁for▁values(값다▁this리)쿼작ality용니수부,▁inequ은▁an사행▁using▁queries▁two"보다 작은 값에 대한 쿼리입니다.equality
동일한 값보다 큰 값에 대한 다른 값.
간단한 예로, 3이 아닌 숫자를 원한다고 가정해 보겠습니다.
const someNumbersThatAreNotThree = someNumbers.filter(n => n !== 3)
라고 쓸 수 있습니다.
const someNumbersThatAreNotThree = [
...someNumbers.filter(n => n < 3),
...someNumbers.filter(n => n > 3)
];
이를 Firestore에 적용하면 다음(이전) 잘못된 쿼리를 변환할 수 있습니다.
const docsWithChallengeID = await colRef
.where('challenge_id', '!=', '')
.get()
.then(querySnapshot => querySnapshot.docs);
다음 두 쿼리로 전환하고 결과를 병합합니다.
const docsWithChallengeID = await Promise.all([
colRef
.orderBy('challenge_id')
.endBefore('')
.get()
.then(querySnapshot => querySnapshot.docs),
colRef
.orderBy('challenge_id')
.startAfter('')
.get()
.then(querySnapshot => querySnapshot.docs),
]).then(results => results.flat());
중요 참고:요청하는 사용자는 권한 오류가 발생하지 않도록 쿼리와 일치하는 모든 문서를 읽을 수 있어야 합니다.
누락/정의되지 않은 필드
간단히 말해, Firestore에서 필드가 문서에 나타나지 않으면 해당 문서는 해당 필드의 색인에 나타나지 않습니다.생략된 필드의 값이 다음과 같은 실시간 데이터베이스와는 대조적입니다.null
.
작업 중인 스키마가 변경되어 이전 문서에 필드가 누락될 수 있는 NoSQL 데이터베이스의 특성으로 인해 "데이터베이스 패치" 솔루션이 필요할 수 있습니다.이렇게 하려면 컬렉션을 반복한 후 새 필드를 누락된 문서에 추가합니다.
사용 권한 오류를 방지하려면 서비스 계정이 있는 Admin SDK를 사용하여 이러한 조정을 수행하는 것이 가장 좋지만 데이터베이스에 대한 적절한 읽기/쓰기 액세스 권한을 가진 사용자를 사용하여 일반 SDK를 사용하여 이 작업을 수행할 수 있습니다.
이 함수는 전체 쿼리를 순환하며 한 번 실행됩니다.
async function addDefaultValueForField(queryRef, fieldName, defaultFieldValue, pageSize = 100) {
let checkedCount = 0, pageCount = 1;
const initFieldPromises = [], newData = { [fieldName]: defaultFieldValue };
// get first page of results
console.log(`Fetching page ${pageCount}...`);
let querySnapshot = await queryRef
.limit(pageSize)
.get();
// while page has data, parse documents
while (!querySnapshot.empty) {
// for fetching the next page
let lastSnapshot = undefined;
// for each document in this page, add the field as needed
querySnapshot.forEach(doc => {
if (doc.get(fieldName) === undefined) {
const addFieldPromise = doc.ref.update(newData)
.then(
() => ({ success: true, ref: doc.ref }),
(error) => ({ success: false, ref: doc.ref, error }) // trap errors for later analysis
);
initFieldPromises.push(addFieldPromise);
}
lastSnapshot = doc;
});
checkedCount += querySnapshot.size;
pageCount++;
// fetch next page of results
console.log(`Fetching page ${pageCount}... (${checkedCount} documents checked so far, ${initFieldPromises.length} need initialization)`);
querySnapshot = await queryRef
.limit(pageSize)
.startAfter(lastSnapshot)
.get();
}
console.log(`Finished searching documents. Waiting for writes to complete...`);
// wait for all writes to resolve
const initFieldResults = await Promise.all(initFieldPromises);
console.log(`Finished`);
// count & sort results
let initializedCount = 0, errored = [];
initFieldResults.forEach((res) => {
if (res.success) {
initializedCount++;
} else {
errored.push(res);
}
});
const results = {
attemptedCount: initFieldResults.length,
checkedCount,
errored,
erroredCount: errored.length,
initializedCount
};
console.log([
`From ${results.checkedCount} documents, ${results.attemptedCount} needed the "${fieldName}" field added.`,
results.attemptedCount == 0
? ""
: ` ${results.initializedCount} were successfully updated and ${results.erroredCount} failed.`
].join(""));
const errorCountByCode = errored.reduce((counters, result) => {
const code = result.error.code || "unknown";
counters[code] = (counters[code] || 0) + 1;
return counters;
}, {});
console.log("Errors by reported code:", errorCountByCode);
return results;
}
그런 다음 다음을 사용하여 변경사항을 적용합니다.
const goalsQuery = firebase.firestore()
.collection("user_goals");
addDefaultValueForField(goalsQuery, "challenge_id", "")
.catch((err) => console.error("failed to patch collection with new default value", err));
또한 문서의 다른 필드를 기준으로 기본값을 계산할 수 있도록 위의 함수를 조정할 수 있습니다.
let getUpdateData;
if (typeof defaultFieldValue === "function") {
getUpdateData = (doc) => ({ [fieldName]: defaultFieldValue(doc) });
} else {
const updateData = { [fieldName]: defaultFieldValue };
getUpdateData = () => updateData;
}
/* ... later ... */
const addFieldPromise = doc.ref.update(getUpdateData(doc))
제가 사용하는 솔루션은 다음과 같습니다.
사용:.where('field', '>', ''),
"필드"는 우리가 찾고 있는 분야입니다!
올바르게 기술한 바와 같이 다음을 기준으로 필터링할 수 없습니다.!=
가능하다면, 목표 유형을 정의하기 위해 추가 필드를 추가하고 싶습니다.사용할 수 있습니다.!=
다양한 문자열 비교 방법과 함께 보안 규칙에서, 당신은 당신을 기반으로 정확한 목표 유형을 시행할 수 있습니다.challenge_id
서식을 정하다
목표 유형 지정
작성type
이 필드를 기준으로 필드 및 필터를 지정합니다.
type: master
또는type: custom
및 검색.where('type', '==', 'master')
또는 사용자 지정을 검색합니다.
사용자 지정 목표 플래그 지정
작성customGoal
될 수 있는 분야true
또는false
.
customGoal: true
및 검색.where('customGoal', '==', true)
또는 false(필요에 따라)
갱신하다
이제 Cloud Firestore에서 != 쿼리를 수행할 수 있습니다.
파이어스토어는 불리언에서 픽업합니다. 이것은 물건입니다! 그리고 가능합니다.orderBy
'd.
지금처럼 이걸 배열에 추가하는 경우가 많습니다.onSnapshot
또는get
,사용하다.get().then(
개발을 위해...
if (this.props.auth !== undefined) {
if (community && community.place_name) {
const sc =
community.place_name && community.place_name.split(",")[1];
const splitComma = sc ? sc : false
if (community.splitComma !== splitComma) {
firebase
.firestore()
.collection("communities")
.doc(community.id)
.update({ splitComma });
}
const sc2 =
community.place_name && community.place_name.split(",")[2];
const splitComma2 =sc2 ? sc2 : false
console.log(splitComma2);
if (community.splitComma2 !== splitComma2) {
firebase
.firestore()
.collection("communities")
.doc(community.id)
.update({
splitComma2
});
}
}
이런 식으로 질문할 수 있습니다.orderBy
에 where
browseCommunities = (paginate, cities) => {
const collection = firebase.firestore().collection("communities");
const query =
cities === 1 //countries
? collection.where("splitComma2", "==", false) //without a second comma
: cities //cities
? collection
.where("splitComma2", ">", "")
.orderBy("splitComma2", "desc") //has at least two
: collection.orderBy("members", "desc");
var shot = null;
if (!paginate) {
shot = query.limit(10);
} else if (paginate === "undo") {
shot = query.startAfter(this.state.undoCommunity).limit(10);
} else if (paginate === "last") {
shot = query.endBefore(this.state.lastCommunity).limitToLast(10);
}
shot &&
shot.onSnapshot(
(querySnapshot) => {
let p = 0;
let browsedCommunities = [];
if (querySnapshot.empty) {
this.setState({
[nuller]: null
});
}
querySnapshot.docs.forEach((doc) => {
p++;
if (doc.exists) {
var community = doc.data();
community.id = doc.id;
이상적인 솔루션은 아니지만 필드가 없는 경우 해결 방법은 다음과 같습니다.
let user_goals = await db.collection('user_goals').get()
user_goals.forEach(goal => {
let data = goal.data()
if(!Object.keys(data).includes(challenge_id)){
//Perform your task here
}
})
이는 읽기 수에 많은 영향을 미치므로 수집이 적거나 읽기를 감당할 수 있는 경우에만 사용하십시오.
const fieldName = 'someField';
db.collectionGroup('students')
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
const documentData = doc.data();
if (!documentData[fieldName]) {
console.log(doc.id);
}
});
});
이 코드를 사용하여 필드가 존재하지 않는 문서를 찾아 인쇄할 수 있습니다.
언급URL : https://stackoverflow.com/questions/49579693/how-do-i-get-documents-where-a-specific-field-exists-does-not-exists-in-firebase
'programing' 카테고리의 다른 글
MongoDB: 로케일:: facet::_S_create_c_local 이름이 잘못되었습니다. (0) | 2023.06.28 |
---|---|
java.java.path의 noocijdbc12 (0) | 2023.06.28 |
R에서 숫자를 백분율로 포맷하는 방법은 무엇입니까? (0) | 2023.06.28 |
GIT에서 부분 되돌리기를 수행할 수 있습니까? (0) | 2023.06.28 |
SQL Server의 모든 데이터베이스에 있는 모든 테이블의 열 이름을 찾는 방법 (0) | 2023.06.28 |