Find
DynamoDB offers three methods to query records: get
, query
, and scan
. In ElectroDB, there is a fourth and fifth type: find
and match
. Unlike get
and query
, the find
method does not require you to provide keys, but under the covers it will leverage the attributes provided to choose the best index to query on. Provide the find
method with all properties known to match a record and ElectroDB will generate the most performant query it can to locate the results. This can be helpful with highly dynamic querying needs. If an index cannot be satisfied with the attributes provided, scan
will be used as a last resort.
The Find method is similar to the Match method with one exception: The attributes you supply directly to the
.find()
method will only be used to identify and fulfill your index access patterns. Any values supplied that do not contribute to a composite key will not be applied as query filters. Furthermore, if the values you provide do not resolve to an index access pattern, then a table scan will be performed. Use thewhere()
chain method to further filter beyond keys, or use Match for the convenience of automatic filtering based on the values given directly to that method.
The Find method is useful when the index chosen does not matter or is not known. If your secondary indexes do not contain all attributes then this method might not be right for you. The mechanism that picks the best index for a given payload is subject to improvement and change without triggering a breaking change release version.
Example Setup
Table Definition
{ "TableName": "electro", "KeySchema": [ { "AttributeName": "pk", "KeyType": "HASH" }, { "AttributeName": "sk", "KeyType": "RANGE" } ], "AttributeDefinitions": [ { "AttributeName": "pk", "AttributeType": "S" }, { "AttributeName": "sk", "AttributeType": "S" }, { "AttributeName": "gsi1pk", "AttributeType": "S" }, { "AttributeName": "gsi1sk", "AttributeType": "S" } ], "GlobalSecondaryIndexes": [ { "IndexName": "gsi1pk-gsi1sk-index", "KeySchema": [ { "AttributeName": "gsi1pk", "KeyType": "HASH" }, { "AttributeName": "gsi1sk", "KeyType": "RANGE" } ], "Projection": { "ProjectionType": "ALL" } }, { "IndexName": "gsi2pk-gsi2sk-index", "KeySchema": [ { "AttributeName": "gsi2pk", "KeyType": "HASH" }, { "AttributeName": "gsi2sk", "KeyType": "RANGE" } ], "Projection": { "ProjectionType": "ALL" } } ], "BillingMode": "PAY_PER_REQUEST" }
(Example code on this page that references the entityExample Entity
import DynamoDB from "aws-sdk/clients/dynamodb"; import { Entity } from "electrodb"; const client = new DynamoDB.DocumentClient(); const table = "electro"; const StoreLocations = new Entity( { model: { service: "MallStoreDirectory", entity: "MallStore", version: "1", }, attributes: { cityId: { type: "string", required: true, }, mallId: { type: "string", required: true, }, storeId: { type: "string", required: true, }, buildingId: { type: "string", required: true, }, unitId: { type: "string", required: true, }, category: { type: [ "spite store", "food/coffee", "food/meal", "clothing", "electronics", "department", "misc", ], required: true, }, leaseEndDate: { type: "string", required: true, }, rent: { type: "string", required: true, validate: /^(\d+\.\d{2})$/, }, discount: { type: "string", required: false, default: "0.00", validate: /^(\d+\.\d{2})$/, }, tenants: { type: "set", items: "string", }, warnings: { type: "number", default: 0, }, deposit: { type: "number", }, contact: { type: "set", items: "string", }, rentalAgreement: { type: "list", items: { type: "map", properties: { type: { type: "string", }, detail: { type: "string", }, }, }, }, petFee: { type: "number", }, fees: { type: "number", }, tags: { type: "set", items: "string", }, }, indexes: { stores: { pk: { field: "pk", composite: ["cityId", "mallId"], }, sk: { field: "sk", composite: ["buildingId", "storeId"], }, }, units: { index: "gsi1pk-gsi1sk-index", pk: { field: "gsi1pk", composite: ["mallId"], }, sk: { field: "gsi1sk", composite: ["buildingId", "unitId"], }, }, leases: { index: "gsi2pk-gsi2sk-index", pk: { field: "gsi2pk", composite: ["storeId"], }, sk: { field: "gsi2sk", composite: ["leaseEndDate"], }, }, }, }, { table, client }, );
StoreLocations
uses the following Entity and Table Definition found below)
await StoreLocations.find({
mallId: "EastPointe",
buildingId: "BuildingA1",
}).go();
Response Format
{
data: Array<YOUR_SCHEMA>,
cursor: string | undefined
}
Equivalent Parameters
{
"KeyConditionExpression": "#pk = :pk and begins_with(#sk1, :sk1)",
"TableName": "StoreDirectory",
"ExpressionAttributeNames": {
"#mallId": "mallId",
"#buildingId": "buildingId",
"#pk": "gsi1pk",
"#sk1": "gsi1sk"
},
"ExpressionAttributeValues": {
":mallId1": "EastPointe",
":buildingId1": "BuildingA1",
":pk": "$mallstoredirectory#mallid_eastpointe",
":sk1": "$mallstore_1#buildingid_buildinga1#unitid_"
},
"IndexName": "gsi1pk-gsi1sk-index"
}
Execution Options
Query options can be added the .params()
and .go()
to change query behavior or add customer parameters to a query.
By default, ElectroDB enables you to work with records as the names and properties defined in the model. Additionally, it removes the need to deal directly with the docClient parameters which can be complex for a team without as much experience with DynamoDB. The Query Options object can be passed to both the .params()
and .go()
methods when building you query. Below are the options available:
{
params?: object;
table?: string;
data?: 'raw' | 'includeKeys' | 'attributes';
pager?: 'raw' | 'cursor';
originalErr?: boolean;
response?: "default" | "none" | "all_old" | "updated_old" | "all_new" | "updated_new";
ignoreOwnership?: boolean;
limit?: number;
count?: number;
pages?: number | 'all';
logger?: (event) => void;
listeners Array<(event) => void>;
attributes?: string[];
order?: 'asc' | 'desc';
compare?: 'attributes' | 'keys' | 'v2';
};
Query Execution Options
params
Default Value: {}
Properties added to this object will be merged onto the params sent to the document client. Any conflicts with ElectroDB will favor the params specified here. Consider this an escape hatch for options not yet supported by ElectroDB.
table
Default Value: (from constructor) Use a different table than the one defined in Service Options and/or Entity Options.
attributes
Default Value: (all attributes)
The attributes
query option allows you to specify ProjectionExpression Attributes for your get
or query
operation.
data
Default Value: "attributes"
Accepts the values 'raw'
, 'includeKeys'
, 'attributes'
or undefined
. Use 'raw'
to return query results as they were returned by the docClient. Use 'includeKeys'
to include item partition and sort key values in your return object. By default, ElectroDB does not return partition, sort, or global keys in its response.
originalErr
Default Value: false
By default, ElectroDB alters the stacktrace of any exceptions thrown by the DynamoDB client to give better visibility to the developer. Set this value equal to true
to turn off this functionality and return the error unchanged.
response
Default Value: "default"
Used as a convenience for applying the DynamoDB parameter ReturnValues
. The options here are the same as the parameter values for the DocumentClient except lowercase. The "none"
option will cause the method to return null and will bypass ElectroDB’s response formatting — useful if formatting performance is a concern.
ignoreOwnership
Default Value: false
By default, ElectroDB interrogates items returned from a query for the presence of matching entity “identifiers”. This helps to ensure other entities, or other versions of an entity, are filtered from your results. If you are using ElectroDB with an existing table/dataset you can turn off this feature by setting this property to true
.
limit
Default Value: none
Used a convenience wrapper for the DynamoDB parameter Limit
[read more].
count
Default Value: none
A target for the number of items to return from DynamoDB. If this option is passed, Queries on entities will paginate DynamoDB until the items found match the count is reached or all items for that query have been returned. It is important to understand that this option may result in ElectroDB making multiple calls to DynamoDB to satisfy the count. For this reason, you should also consider using the pages
option to limit the number of requests (or “pages”) made to DynamoDB.
pages
Default Value: 1
How many DynamoDB pages should a query iterate through before stopping. To have ElectroDB automatically paginate through all results, pass the string value 'all'
.
order
Default Value: ‘asc’
Convenience option for ScanIndexForward
, to the change the order of queries based on your index’s Sort Key — valid options include ‘asc’ and ‘desc’. [read more]
listeners
Default Value: []
An array of callbacks that are invoked when internal ElectroDB events occur.
logger
Default Value: none A convenience option for a single event listener that semantically can be used for logging.
compare
Default Value: ‘keys’
When performing comparison queries (e.g. gt
, gte
, lte
, lt
, between
) it is often necessary to add additional filters. Understanding how a comparison query will impact the items returned can be challenging due to the unintuitive nature of sorting and multi-composite attribute Sort Keys.
By default (comparison: "keys"
), ElectroDB builds comparison queries without applying attribute filters. In this way, the query’s comparison applies to the item’s “keys”. This approach gives you complete control of your indexes, though your query may return unexpected data if you are not careful with item sorting.
When set to attributes
, the comparison
option instructs ElectroDB to apply attribute filters on each Sort Key composite attribute provided. In this way, the query comparison applies to the item’s “attributes.”