Datastore 모드의 Firestore는 단일 쿼리의 여러 속성에 범위 및 불일치 필터 사용을 지원합니다. 이 기능을 사용하면 여러 속성에 범위 및 불일치 조건을 적용할 수 있고, 사후 필터링 로직 구현을 Datastore 모드의 Firestore에 위임하여 애플리케이션 개발을 간소화할 수 있습니다.
여러 속성의 범위 및 불일치 필터
다음 쿼리는 우선순위 및 일수에 범위 필터를 사용하여 우선순위가 4보다 크고 3일 내에 완료되는 모든 태스크를 반환합니다.
ORDER BY 절이 지정되지 않은 경우 Datastore 모드의 Firestore는 쿼리의 필터 조건을 충족할 수 있는 색인을 사용하여 쿼리를 처리합니다. 이 방식은 색인 정의에 따라 정렬된 결과 집합을 생성합니다.
Datastore 모드의 Firestore 쿼리의 성능과 비용을 최적화하려면 색인의 속성 순서를 최적화합니다. 이렇게 하려면 쿼리가 불필요한 색인 항목의 스캔을 방지하는 데이터 세트로 정리되도록 색인을 왼쪽에서 오른쪽으로 정렬합니다.
예를 들어 직원 컬렉션을 검색하여 급여가 100,000달러를 초과하고 경력 연수가 0년을 넘는 미국 직원을 찾는다고 가정해 보겠습니다. 데이터 세트에 대한 이해를 바탕으로 급여 제약조건이 경력 제약조건보다 더 선택적이라는 것을 알 수 있습니다. 색인 스캔 횟수를 줄이는 색인은 (salary [...], experience [...]) 색인입니다. 따라서 다음 예시와 같이 빠르고 비용 효율적인 쿼리가 experience보다 salary를 먼저 정렬합니다.
Datastore 모드의 Firestore는 복합 색인의 가장 왼쪽 속성을 사용하여 orderBy() 쿼리의 첫 번째 필드에서 일치 제약조건과 범위 및 불일치 제약조건(있는 경우)을 충족합니다. 이러한 제약조건을 통해 Datastore 모드의 Firestore가 스캔하는 색인 항목 수를 줄일 수 있습니다. Datastore 모드의 Firestore는 색인의 나머지 속성을 사용하여 쿼리의 다른 범위 및 불일치 제약조건을 충족합니다. 이러한 제약조건은 Datastore 모드의 Firestore가 스캔하는 색인 항목 수를 줄이지는 않지만 일치하지 않는 항목을 필터링하여 클라이언트에 반환되는 항목 수를 줄입니다.
Datastore 모드의 Firestore가 쿼리에 가장 적합한 색인을 선택하도록 하려면 쿼리의 제약조건 선택성에 따라 범위 및 불일치 속성 순서를 선택성이 높은 순으로 지정하는 orderBy() 절을 지정합니다. 선택성이 높을수록 더 적은 항목과 일치하고 선택성이 낮을수록 더 많은 항목과 일치합니다. 색인 순서에서 선택성이 높은 범위 및 불일치 속성을 선택성이 낮은 속성 앞에 배치합니다.
Datastore 모드의 Firestore가 네트워크를 통해 스캔하여 반환하는 항목 수를 최소화하려면 항상 쿼리 제약조건 선택성의 내림차순으로 속성 순서를 지정해야 합니다. 결과 집합이 필요한 순서가 아니며 결과 집합이 작을 것으로 예상되는 경우 클라이언트 측 로직을 구현하여 예상되는 순서에 따라 순서를 다시 지정할 수 있습니다.
예를 들어 직원 컬렉션을 검색하여 급여가 100,000달러를 초과하는 미국 직원을 찾아 이러한 직원의 경력 연수를 기준으로 결과를 정렬한다고 가정해 보겠습니다. 급여가 100,000달러를 초과할 것으로 예상되는 직원 수가 많지 않을 경우 쿼리를 작성하는 효율적인 방법은 다음과 같습니다.
자바
Query<Entity>query=Query.newEntityQueryBuilder().setKind("employees").setFilter(PropertyFilter.gt("salary",100000)).setOrderBy(OrderBy("salary")).build();QueryResults<Entity>results=datastore.run(query);// Order results by `experience`
Node.js
constquery=datastore.createQuery("employees").filter(newPropertyFilter("salary",">",100000)).order("salary");const[entities]=awaitdatastore.runQuery(query);// Order results by `experience`
쿼리에 experience의 순서를 추가하면 동일한 항목 집합이 생성되고 클라이언트에서 결과가 다시 정렬되지 않지만 쿼리가 관련 없는 색인 항목을 이전 쿼리보다 더 많이 읽을 수 있습니다. 이는 Datastore 모드의 Firestore가 항상 색인 속성 프리픽스가 쿼리의 ORDER BY 절과 일치하는 색인을 선호하기 때문입니다. experience가 ORDER BY 절에 추가된 경우 Datastore 모드의 Firestore는 쿼리 결과 계산을 위해 (experience [...], salary [...]) 색인을 선택합니다. experience에는 다른 제약조건이 없으므로 Datastore 모드의 Firestore는 salary 필터를 적용하여 최종 결과 집합을 찾기 전에 employees 컬렉션의 모든 색인 항목을 읽습니다. 즉, salary 필터를 충족하지 않는 색인 항목이 계속 읽히므로 쿼리 지연 시간과 비용이 증가합니다.
가격 책정
여러 속성에 범위 및 불일치 필터가 있는 쿼리에는 항목 읽기 및 색인 항목 읽기를 기준으로 요금이 청구됩니다.
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["이해하기 어려움","hardToUnderstand","thumb-down"],["잘못된 정보 또는 샘플 코드","incorrectInformationOrSampleCode","thumb-down"],["필요한 정보/샘플이 없음","missingTheInformationSamplesINeed","thumb-down"],["번역 문제","translationIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2025-09-08(UTC)"],[[["\u003cp\u003eFirestore in Datastore mode allows for range and inequality filters on multiple properties within a single query, simplifying application development.\u003c/p\u003e\n"],["\u003cp\u003eQueries with multiple range and inequality filters can be optimized by ordering properties in the index from most to least selective, to minimize index scans.\u003c/p\u003e\n"],["\u003cp\u003eWhen using the \u003ccode\u003eorderBy()\u003c/code\u003e clause, ensure that it prioritizes equality constraints and the most selective range or inequality fields, followed by other constraints.\u003c/p\u003e\n"],["\u003cp\u003eQueries are billed based on the number of entities and index entries read, and there is a limitation of up to 10 range or inequality operators per query.\u003c/p\u003e\n"],["\u003cp\u003eIt's recommended to read about query optimization, index usage, and performing simple and compound queries for a deeper understanding.\u003c/p\u003e\n"]]],[],null,["# Query with range and inequality filters on multiple properties overview\n\nFirestore in Datastore mode supports using range and inequality filters on multiple properties in a single query. This feature gives you range and inequality conditions on multiple properties and simplifies\nyour application development by delegating implementation of post-filtering\nlogic to Firestore in Datastore mode.\n\nRange and inequality filters on multiple properties\n---------------------------------------------------\n\nThe following query uses range filters on priority and days to return all tasks\nwith priority greater than four and with less than three days to complete. \n\n### Go\n\n query := datastore.NewQuery(\"Task\").\n FilterField(\"priority\", \"\u003e\", 4).\n FilterField(\"days\", \"\u003c\", 3).\n\n### GQL\n\n SELECT * FROM /tasks WHERE priority \u003e 4 AND days \u003c 3;\n\n### Java\n\n Query\u003cEntity\u003e query =\n Query.newEntityQueryBuilder()\n .setKind(\"Task\")\n .setFilter(\n CompositeFilter.and(\n PropertyFilter.gt(\"priority\", 4), PropertyFilter.lt(\"days\", 3)))\n .build();\n\n### Node.js\n\n const query = datastore\n .createQuery('Task')\n .filter(\n and([\n new PropertyFilter('priority', '\u003e', 4),\n new PropertyFilter('days', '\u003c', 3),\n ])\n );\n\n### Python\n\n from google.cloud import https://cloud.google.com/python/docs/reference/datastore/latest/\n client = https://cloud.google.com/python/docs/reference/datastore/latest/.https://cloud.google.com/python/docs/reference/datastore/latest/google.cloud.datastore.client.Client.html()\n query = client.https://cloud.google.com/python/docs/reference/datastore/latest/google.cloud.datastore.client.Client.html#google_cloud_datastore_client_Client_query(kind=\"Task\")\n query.https://cloud.google.com/python/docs/reference/datastore/latest/google.cloud.datastore.query.Query.html#google_cloud_datastore_query_Query_add_filter(filter=PropertyFilter(\"priority\", \"\u003e\", 4))\n query.https://cloud.google.com/python/docs/reference/datastore/latest/google.cloud.datastore.query.Query.html#google_cloud_datastore_query_Query_add_filter(filter=PropertyFilter(\"days\", \"\u003c\", 3))\n\n### PHP\n\n $query = $datastore-\u003equery()\n -\u003ekind('Task')\n -\u003efilter('priority', '\u003e', 4)\n -\u003efilter('days', '\u003c', 3)\n\n### C#\n\n Query query = new Query(\"Task\")\n {\n Filter = Filter.And(Filter.GreaterThan(\"priority\", 4),\n Filter.LessThan(\"days\", 3))\n };\n\n### Ruby\n\n query = datastore.query(\"Task\")\n .where(\"priority\", \"\u003e\", 4)\n .where(\"days\", \"\u003c\", 3)\n\nIndexing considerations\n-----------------------\n\nBefore you start running queries, make sure you have read\nabout [queries](/datastore/docs/concepts/queries).\n\nIf an `ORDER BY` clause isn't specified, Firestore in Datastore mode uses any index that\ncan satisfy the query's filter condition to serve the query. This approach produces a result\nset that is ordered according to the index definition.\n\nTo optimize the performance and cost of Firestore in Datastore mode queries,\noptimize the order of properties in the index. To do this, ensure that your\nindex is ordered from left to right so that the query distills to a\ndataset that prevents scanning of extraneous index entries.\n\nFor example, suppose you want to search through a collection of employees to\nfind United States employees whose salary is more than $100,000 and whose number\nof years of experience is greater than 0. Based on your understanding of the\ndataset, you know that the salary constraint is more selective than the\nexperience constraint. An index that reduces the number of index scans is the\n`(salary [...], experience [...])` index. As a result, a fast and cost-efficient\nquery orders `salary` before `experience`, as shown in the following example: \n\n### GQL\n\n SELECT *\n FROM /employees\n WHERE salary \u003e 100000 AND experience \u003e 0\n ORDER BY salary, experience\n\n### Java\n\n Query\u003cEntity\u003e query =\n Query.newEntityQueryBuilder()\n .setKind(\"employees\")\n .setFilter(\n CompositeFilter.and(\n PropertyFilter.gt(\"salary\", 100000), PropertyFilter.gt(\"experience\", 0)))\n .setOrderBy(OrderBy(\"salary\"), OrderBy(\"experience\"))\n .build();\n\n### Node.js\n\n const query = datastore\n .createQuery(\"employees\")\n .filter(\n and([\n new PropertyFilter(\"salary\", \"\u003e\", 100000),\n new PropertyFilter(\"experience\", \"\u003e\", 0),\n ])\n )\n .order(\"salary\")\n .order(\"experience\");\n\n### Python\n\n query = client.query(kind=\"employees\")\n query.add_filter(\"salary\", \"\u003e\", 100000)\n query.add_filter(\"experience\", \"\u003e\", 0)\n query.order = [\"-salary\", \"-experience\"]\n\nBest practices for optimizing indexes\n-------------------------------------\n\nWhen optimizing indexes, note the following best practices.\n\n#### Order queries by equalities followed by most selective range or inequality field\n\nFirestore in Datastore mode uses the leftmost properties of a composite index to satisfy\nthe equality constraints and the range and inequality constraint, if any, on the\nfirst field of the `orderBy()` query. These constraints can reduce the number of\nindex entries that Firestore in Datastore mode scans. Firestore in Datastore mode uses the remaining\nproperties of the index to satisfy other range and inequality constraints of the\nquery. These constraints don't reduce the number of index entries that\nFirestore in Datastore mode scans, but they filter out unmatched entities so that the number of\nentities that are returned to the clients are reduced.\n\nFor more information about creating efficient indexes, see [index structure and\ndefinition](/datastore/docs/concepts/indexes) and [optimizing indexes](/datastore/docs/concepts/optimize-indexes).\n\n#### Order properties in decreasing order of query constraint selectivity\n\nTo ensure that Firestore in Datastore mode selects the optimal index for your query,\nspecify an `orderBy()` clause that orders range and inequality properties based\non how selective their constraints are in your query, starting from the most\nselective. Higher selectivity matches fewer entities, while lower selectivity\nmatches more entities. In your index ordering, put range and inequality\nproperties with higher selectivity before properties with lower selectivity.\n\nTo minimize the number of entities that Firestore in Datastore mode scans and returns over\nthe network, you should always order properties in the decreasing order of query\nconstraint selectivity. If the result set is not in the required order and the\nresult set is expected to be small, you can implement client-side logic to\nreorder it as per your ordering expectation.\n\nFor example, if you want to search through a collection of employees to\nfind United States employees whose salary is more than $100,000 and order the results by the\nyear of experience of the employee. If you expect that only a small number of\nemployees will have salary higher than $100,000, then an efficient way to\nwrite the query is as follows: \n\n### Java\n\n Query\u003cEntity\u003e query =\n Query.newEntityQueryBuilder()\n .setKind(\"employees\")\n .setFilter(PropertyFilter.gt(\"salary\", 100000))\n .setOrderBy(OrderBy(\"salary\"))\n .build();\n QueryResults\u003cEntity\u003e results = datastore.run(query);\n // Order results by `experience`\n\n### Node.js\n\n const query = datastore\n .createQuery(\"employees\")\n .filter(new PropertyFilter(\"salary\", \"\u003e\", 100000))\n .order(\"salary\");\n const [entities] = await datastore.runQuery(query);\n // Order results by `experience`\n\n### Python\n\n query = client.query(kind=\"employees\")\n query.add_filter(\"salary\", \"\u003e\", 100000)\n query.order = [\"salary\"]\n results = query.fetch()\n // Order results by `experience`\n\nWhile adding an ordering on `experience` to the query will yield the same set\nof entities and obviate re-ordering the results on the clients, the query may\nread many more extraneous index entries than the earlier query. This is because\nFirestore in Datastore mode always prefers an index whose index properties prefix match the\norder by clause of the query. If `experience` were added to the order by clause,\nthen Firestore in Datastore mode will select the `(experience [...], salary [...])` index\nfor computing query results. Since there are no other constraints on\n`experience`, Firestore in Datastore mode will read **all** index entries of the\n`employees` collection before applying the `salary` filter to find the final\nresult set. This means that index entries which don't satisfy the `salary`\nfilter are still read, thus increasing the latency and cost of the query.\n\nPricing\n-------\n\nQueries with range and inequality filters on multiple properties are billed\nbased on entities read and index entries read.\n\nFor detailed information, see the [Pricing](/datastore/docs/pricing) page.\n\nLimitations\n-----------\n\nApart from the [query limitations](/datastore/docs/concepts/queries#limitations_2), note the following limitations before\nusing queries with range and inequality filters on multiple properties:\n\n- To prevent queries from becoming too expensive to run, Firestore in Datastore mode limits the number of range or inequality operators to 10.\n\nWhat's Next\n-----------\n\n- Learn about [optimizing your queries](/datastore/docs/multiple-range-optimize-indexes).\n- Learn more about [performing simple and compound queries](/datastore/docs/concepts/queries).\n- Understand how [Firestore in Datastore mode uses indexes](/datastore/docs/concepts/indexes)."]]