From 213cdf542b7835781a78d1c89803996643d9f140 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Mar 2026 14:01:57 +0000 Subject: [PATCH 1/4] Initial plan From dc0fcb907202e7b1985340f607dae0f8f4ac0512 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Mar 2026 14:08:19 +0000 Subject: [PATCH 2/4] feat(firestore): add collection group and nested path query support - Add --collection-group / -g flag to firestore:query command to query all subcollections with a given name across the entire database using db.collectionGroup() - Extract parseWhereValue() and applyCollectionQueryConstraints() helpers to eliminate duplication between queryCollectionData and the new queryCollectionGroupData function - Add queryCollectionGroupData() action with full output support (console, --json, --output), including index-requirement notice - Update firestore:query help text with subcollection and collection group examples - Update README.md command descriptions and examples for both Firestore nested/group queries and RTDB nested path/field queries - Update llm.txt with Nested Path Queries section covering Firestore subcollections, collection groups, and RTDB deep paths and field filters Co-authored-by: omer-ayhan <32736625+omer-ayhan@users.noreply.github.com> --- README.md | 21 +- llm.txt | 31 ++- src/actions/firestore/firestore-query.ts | 252 +++++++++++++++++++--- src/commands/firestore/firestore-query.ts | 18 +- 4 files changed, 286 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index fb623b1..34a5c69 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Below is a brief list of the available commands and their function: | **firestore:export** | Export all collections from Firestore to a single compact importable JSON file (`firestore_export.json`). Supports subcollection handling and collection exclusions. | | **firestore:import** | Import data to Firestore from JSON file. Supports batch operations and merge functionality. | | **firestore:list** | List all collections and their basic information from the current project's Firestore database. | -| **firestore:query** | Query a collection or fetch a specific document. Supports advanced filtering, ordering, and field-specific queries. | +| **firestore:query** | Query a collection or fetch a specific document. Supports subcollection paths (e.g., `users user1 orders`), collection group queries (`--collection-group`), advanced filtering, ordering, and field-specific queries. | ### Realtime Database Commands @@ -78,7 +78,7 @@ Below is a brief list of the available commands and their function: | **rtdb:export** | Export all data from Realtime Database to a single compact importable JSON file (`rtdb_export.json`). Supports exclusion options and top-level-only export. | | **rtdb:import** | Import data to Realtime Database from JSON file. Supports batch operations and merge functionality. | | **rtdb:list** | List all top-level nodes and their basic information from the current project's Realtime Database. | -| **rtdb:query** | Query a specific path in Realtime Database. Supports filtering, ordering, and JSON output with file saving. | +| **rtdb:query** | Query a specific path in Realtime Database. Supports deep nested paths (e.g., `/root/a/b/c`), nested field filters (`field/subfield,==,value`), ordering, and JSON output with file saving. | ### Remote Config Commands @@ -127,12 +127,29 @@ firebase-tools-cli rtdb:import ./rtdb-backup/rtdb_export.json --database-url htt firebase-tools-cli firestore:query users --where "age,>=,18" --limit 10 firebase-tools-cli firestore:query users --order-by "name,asc" +# Query Firestore subcollections (nested paths) +firebase-tools-cli firestore:query users user1 orders +firebase-tools-cli firestore:query users user1 orders --where "status,==,shipped" --limit 5 +firebase-tools-cli firestore:query users user1 orders order1 + +# Query Firestore collection groups (all subcollections with the same name) +firebase-tools-cli firestore:query orders --collection-group +firebase-tools-cli firestore:query orders --collection-group --where "status,==,shipped" --limit 20 + # Query specific document fields firebase-tools-cli firestore:query users user1 --field profile.settings # Query Realtime Database with filtering firebase-tools-cli rtdb:query users --where "age,>=,18" --limit 10 --database-url https://my-project-rtdb.firebaseio.com/ firebase-tools-cli rtdb:query posts --order-by "timestamp,desc" --json --output results.json + +# Query Realtime Database at a nested path +firebase-tools-cli rtdb:query users/user4/active --database-url https://my-project-rtdb.firebaseio.com/ +firebase-tools-cli rtdb:query users user4 active --database-url https://my-project-rtdb.firebaseio.com/ + +# Query Realtime Database with nested field filters +firebase-tools-cli rtdb:query users --where "workouts/appVersion,==,2.3.1" --database-url https://my-project-rtdb.firebaseio.com/ +firebase-tools-cli rtdb:query workouts --where "settings/difficulty,>=,3" --order-by "settings/duration,desc" --database-url https://my-project-rtdb.firebaseio.com/ ``` ### Remote Config Management diff --git a/llm.txt b/llm.txt index 9d3f688..a8b9f0e 100644 --- a/llm.txt +++ b/llm.txt @@ -31,10 +31,12 @@ A comprehensive command-line interface for Firebase Firestore database operation - `-m, --merge` - Merge documents instead of overwriting - `-e, --exclude ` - Exclude specific collections -- `firebase-tools-cli query ` - Query a specific collection +- `firebase-tools-cli query ` - Query a specific collection or document - `-w, --where ` - Where clause (e.g., "age,>=,18") - `-l, --limit ` - Limit number of results - `-o, --order-by ` - Order by field (e.g., "name,asc") + - `-f, --field ` - Show specific field from document (document queries only) + - `-g, --collection-group` - Query as a collection group across all matching subcollections - `--json` - Output results as JSON - `--output ` - Save JSON output to file @@ -146,6 +148,33 @@ Supported Firestore query operators: - `in` - Value is in array - `not-in` - Value is not in array +## Nested Path Queries + +### Firestore Subcollections +Use space-separated path segments to target subcollections. Odd segments = collection query, even segments = document query: +- `firestore:query users` - Query top-level `users` collection +- `firestore:query users user1 orders` - Query `orders` subcollection under `users/user1` +- `firestore:query users user1 orders order42` - Fetch specific document `users/user1/orders/order42` +- `firestore:query users user1 orders --where "status,==,shipped"` - Filter subcollection + +### Firestore Collection Group Queries +Use `--collection-group` (`-g`) to query all subcollections with a given name across the entire database: +- `firestore:query orders --collection-group` - Query all `orders` subcollections +- `firestore:query orders --collection-group --where "status,==,shipped" --limit 20` +- **Requires a Firestore composite index** - follow the error link to create it in Firebase Console if needed. + +### RTDB Nested Paths +Specify deep paths using either slash-separated or space-separated segments: +- `rtdb:query users/user4/active` - Query at path `/users/user4/active` +- `rtdb:query users user4 active` - Same as above (space-separated) +- `rtdb:query root/a/b/c` - Query at arbitrary depth + +### RTDB Nested Field Filters +Use `/`-separated field paths in `--where` and `--order-by` to filter on nested fields: +- `rtdb:query users --where "workouts/appVersion,==,2.3.1"` - Filter on nested field +- `rtdb:query workouts --order-by "settings/duration,desc"` - Sort by nested field +- `rtdb:query workouts --where "settings/difficulty,>=,3" --order-by "settings/duration,asc"` - Combine both + ## Configuration Files - `~/.firebase-tools-cli/config.json` - Default project and settings - `~/.firebase-tools-cli/credentials.json` - OAuth credentials (auto-managed) diff --git a/src/actions/firestore/firestore-query.ts b/src/actions/firestore/firestore-query.ts index e447a36..daee0c0 100644 --- a/src/actions/firestore/firestore-query.ts +++ b/src/actions/firestore/firestore-query.ts @@ -9,6 +9,7 @@ type QueryCommandOptionsType = { field?: string; json?: boolean; output?: string; + collectionGroup?: boolean; }; type QueryDocumentSnapshotType = admin.firestore.QueryDocumentSnapshot< @@ -125,6 +126,29 @@ export async function queryCollection( const db = admin.firestore(); + // Collection group query: queries all subcollections with this name across the entire database + if (options.collectionGroup) { + if (collectionPath.length !== 1) { + throw new Error( + '--collection-group requires exactly one collection ID (e.g., firestore:query orders --collection-group)' + ); + } + if (options.field) { + console.log( + chalk.yellow( + '⚠️ --field option is only available for document queries, not collection group queries' + ) + ); + } + await queryCollectionGroupData( + db, + collectionPath[0], + options, + collectionPathStr + ); + return; + } + // Check if we're querying a document or a collection const isDocumentQuery = collectionPath.length % 2 === 0; @@ -561,6 +585,51 @@ async function queryDocument( } } +// Helper function to parse a where-clause value string to the appropriate JS type +function parseWhereValue(raw: string): string | number | boolean | null { + if (raw === 'true') return true; + if (raw === 'false') return false; + if (raw === 'null') return null; + if (!isNaN(Number(raw))) return Number(raw); + return raw; +} + +// Helper function to apply where/limit/orderBy constraints to a Firestore query +function applyCollectionQueryConstraints( + query: admin.firestore.Query< + admin.firestore.DocumentData, + admin.firestore.DocumentData + >, + options: QueryCommandOptionsType +): admin.firestore.Query< + admin.firestore.DocumentData, + admin.firestore.DocumentData +> { + if (options.where) { + const [field, operator, value] = options.where.split(','); + const operatorType = operator.trim() as admin.firestore.WhereFilterOp; + const parsedValue = parseWhereValue(value.trim()); + query = query.where(field.trim(), operatorType, parsedValue); + console.log( + chalk.gray(` └── Filter: ${field} ${operator} ${parsedValue}`) + ); + } + + if (options.limit) { + query = query.limit(parseInt(options.limit)); + console.log(chalk.gray(` └── Limit: ${options.limit}`)); + } + + if (options.orderBy) { + const [field, direction] = options.orderBy.split(','); + const directionType = direction?.trim() as admin.firestore.OrderByDirection; + query = query.orderBy(field.trim(), directionType || 'asc'); + console.log(chalk.gray(` └── Order: ${field} ${direction || 'asc'}`)); + } + + return query; +} + async function queryCollectionData( db: admin.firestore.Firestore, collectionPath: string[], @@ -594,38 +663,7 @@ async function queryCollectionData( >; } - // Apply where clause - if (options.where) { - const [field, operator, value] = options.where.split(','); - const operatorType = operator.trim() as admin.firestore.WhereFilterOp; - - // Parse value to appropriate type - let parsedValue: any = value.trim(); - if (parsedValue === 'true') parsedValue = true; - else if (parsedValue === 'false') parsedValue = false; - else if (parsedValue === 'null') parsedValue = null; - else if (!isNaN(Number(parsedValue))) parsedValue = Number(parsedValue); - - query = query.where(field.trim(), operatorType, parsedValue); - console.log( - chalk.gray(` └── Filter: ${field} ${operator} ${parsedValue}`) - ); - } - - // Apply limit - if (options.limit) { - query = query.limit(parseInt(options.limit)); - console.log(chalk.gray(` └── Limit: ${options.limit}`)); - } - - // Apply ordering - if (options.orderBy) { - const [field, direction] = options.orderBy.split(','); - const directionType = direction?.trim() as admin.firestore.OrderByDirection; - - query = query.orderBy(field.trim(), directionType || 'asc'); - console.log(chalk.gray(` └── Order: ${field} ${direction || 'asc'}`)); - } + query = applyCollectionQueryConstraints(query, options); const snapshot = await query.get(); @@ -744,3 +782,153 @@ async function queryCollectionData( console.log(chalk.gray(` └── Project: ${admin.app().options.projectId}`)); } } + +async function queryCollectionGroupData( + db: admin.firestore.Firestore, + collectionId: string, + options: QueryCommandOptionsType, + collectionPathStr: string +) { + console.log( + chalk.cyan( + `🌐 Collection group query: searching all "${collectionId}" subcollections across the database\n` + ) + ); + console.log( + chalk.gray( + ' ⚠️ Note: Collection group queries require a Firestore composite index.' + ) + ); + console.log( + chalk.gray( + ' If this query fails with an index error, follow the link in the error' + ) + ); + console.log( + chalk.gray( + ' message to create the required index in Firebase Console.\n' + ) + ); + + let query: admin.firestore.Query< + admin.firestore.DocumentData, + admin.firestore.DocumentData + > = db.collectionGroup(collectionId); + + query = applyCollectionQueryConstraints(query, options); + + const snapshot = await query.get(); + + if (snapshot.size === 0) { + console.log(chalk.yellow('⚠️ No documents found matching the query')); + return; + } + + console.log(chalk.green(`✅ Found ${snapshot.size} document(s)\n`)); + + // Collect results for JSON output + const results: any[] = []; + + snapshot.forEach((doc: QueryDocumentSnapshotType) => { + const docData = { + id: doc.id, + path: doc.ref.path, + data: doc.data(), + createTime: doc.createTime, + updateTime: doc.updateTime, + }; + + results.push(docData); + + // Only show console output if not JSON mode + if (!options.json) { + console.log(chalk.white(`📁 ${doc.id}`)); + console.log(chalk.gray(` └── Path: ${doc.ref.path}`)); + + // Show field values in detail + const data = doc.data(); + const entries = Object.entries(data); + + // Show up to 10 fields to prevent overwhelming output + const maxDisplay = 10; + const displayEntries = entries.slice(0, maxDisplay); + + for (const [key, value] of displayEntries) { + let displayValue: string; + + if (typeof value === 'object' && value !== null) { + if (Array.isArray(value)) { + displayValue = `[Array with ${value.length} items]`; + } else { + displayValue = `[Object with ${Object.keys(value).length} keys]`; + } + } else if (typeof value === 'string' && value.length > 50) { + displayValue = `${value.substring(0, 50)}...`; + } else { + displayValue = String(value); + } + + console.log(chalk.gray(` └── ${key}: ${displayValue}`)); + } + + if (entries.length > maxDisplay) { + console.log( + chalk.gray( + ` └── ... and ${entries.length - maxDisplay} more fields` + ) + ); + } + + console.log(); + } + }); + + // Prepare output data + const outputData = { + type: 'collection_group', + collectionId: collectionId, + query: { + ...(options.where && { where: options.where }), + ...(options.limit && { limit: parseInt(options.limit) }), + ...(options.orderBy && { orderBy: options.orderBy }), + }, + summary: { + totalDocuments: snapshot.size, + }, + results: results, + timestamp: new Date().toISOString(), + }; + + // Handle file output + if (options.output) { + const outputFile = options.output.endsWith('.json') + ? options.output + : `${options.output}.json`; + + fs.writeFileSync(outputFile, JSON.stringify(outputData, null, 2)); + console.log(chalk.green(`📄 Query results saved to: ${outputFile}`)); + + const fileSize = (fs.statSync(outputFile).size / 1024).toFixed(2); + console.log(chalk.gray(` └── File size: ${fileSize} KB`)); + } + + // Handle JSON console output + if (options.json) { + console.log(JSON.stringify(outputData, null, 2)); + } else if (!options.output) { + // Show detailed summary only if not in JSON mode and no file output + console.log(chalk.blue('📊 Collection Group Query Summary:')); + console.log(chalk.gray(` └── Collection ID: ${collectionId}`)); + console.log(chalk.gray(` └── Total documents: ${snapshot.size}`)); + if (options.where) { + console.log(chalk.gray(` └── Where: ${options.where}`)); + } + if (options.orderBy) { + console.log(chalk.gray(` └── Order by: ${options.orderBy}`)); + } + if (options.limit) { + console.log(chalk.gray(` └── Limit: ${options.limit}`)); + } + console.log(chalk.gray(` └── Project: ${admin.app().options.projectId}`)); + } +} diff --git a/src/commands/firestore/firestore-query.ts b/src/commands/firestore/firestore-query.ts index 64741e8..07af35c 100644 --- a/src/commands/firestore/firestore-query.ts +++ b/src/commands/firestore/firestore-query.ts @@ -24,6 +24,10 @@ const firestoreQuery = program '-f, --field ', 'Show only specific field(s) from document (e.g., "pages" or "pages.0.title") - only for document queries' ) + .option( + '-g, --collection-group', + 'Query as a collection group - searches all subcollections with this name across the entire database (requires a Firestore index)' + ) .option('--json', 'Output results as JSON') .option('--output ', 'Save JSON output to file') .addHelpText( @@ -41,6 +45,16 @@ Examples: $ firebase-tools-cli firestore:query users user1 posts post1 $ firebase-tools-cli firestore:query users user1 posts post1 comments comment1 + Subcollection queries (nested paths): + $ firebase-tools-cli firestore:query users user1 orders + $ firebase-tools-cli firestore:query users user1 orders --where "status,==,shipped" --limit 5 + $ firebase-tools-cli firestore:query users user1 orders order1 + + Collection group queries (across all subcollections with this name): + $ firebase-tools-cli firestore:query orders --collection-group + $ firebase-tools-cli firestore:query orders --collection-group --where "status,==,shipped" + $ firebase-tools-cli firestore:query orders --collection-group --order-by "createdAt,desc" --limit 20 + Field-specific queries (document queries only): $ firebase-tools-cli firestore:query mobile_onboardings 1 --field pages $ firebase-tools-cli firestore:query users user1 --field profile.settings @@ -53,7 +67,9 @@ Examples: $ firebase-tools-cli firestore:query posts post1 --field comments --where "rating,>=,4" --order-by "timestamp,desc" Note: Query options (--where, --limit, --order-by) apply to collection queries and document array fields. -Field queries (--field) only apply to document queries.` +Field queries (--field) only apply to document queries. +Collection group queries (--collection-group) may require a Firestore composite index - follow +the link in the error message to create it in Firebase Console if needed.` ) .action(async (collection, subcollections, options) => { try { From 742d9a5362540dde1d407d06122f6471f4772046 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Mar 2026 14:27:07 +0000 Subject: [PATCH 3/4] fix(firestore): remove unused param and fix collection group index warning accuracy - Remove unused collectionPathStr parameter from queryCollectionGroupData - Show the Firestore index warning only when --where or --order-by is specified (simple collection group queries do not require an index) - Update --collection-group option description and help text to reflect that only filtered/ordered queries may require an index Co-authored-by: omer-ayhan <32736625+omer-ayhan@users.noreply.github.com> --- llm.txt | 2 +- src/actions/firestore/firestore-query.ts | 43 +++++++++++------------ src/commands/firestore/firestore-query.ts | 4 +-- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/llm.txt b/llm.txt index a8b9f0e..818c17a 100644 --- a/llm.txt +++ b/llm.txt @@ -161,7 +161,7 @@ Use space-separated path segments to target subcollections. Odd segments = colle Use `--collection-group` (`-g`) to query all subcollections with a given name across the entire database: - `firestore:query orders --collection-group` - Query all `orders` subcollections - `firestore:query orders --collection-group --where "status,==,shipped" --limit 20` -- **Requires a Firestore composite index** - follow the error link to create it in Firebase Console if needed. +- **Filtered/ordered queries may require a Firestore composite index** - follow the error link to create it in Firebase Console if needed. ### RTDB Nested Paths Specify deep paths using either slash-separated or space-separated segments: diff --git a/src/actions/firestore/firestore-query.ts b/src/actions/firestore/firestore-query.ts index daee0c0..daee0a6 100644 --- a/src/actions/firestore/firestore-query.ts +++ b/src/actions/firestore/firestore-query.ts @@ -140,12 +140,7 @@ export async function queryCollection( ) ); } - await queryCollectionGroupData( - db, - collectionPath[0], - options, - collectionPathStr - ); + await queryCollectionGroupData(db, collectionPath[0], options); return; } @@ -786,30 +781,32 @@ async function queryCollectionData( async function queryCollectionGroupData( db: admin.firestore.Firestore, collectionId: string, - options: QueryCommandOptionsType, - collectionPathStr: string + options: QueryCommandOptionsType ) { console.log( chalk.cyan( `🌐 Collection group query: searching all "${collectionId}" subcollections across the database\n` ) ); - console.log( - chalk.gray( - ' ⚠️ Note: Collection group queries require a Firestore composite index.' - ) - ); - console.log( - chalk.gray( - ' If this query fails with an index error, follow the link in the error' - ) - ); - console.log( - chalk.gray( - ' message to create the required index in Firebase Console.\n' - ) - ); + // Only filtered/ordered collection group queries require a Firestore index + if (options.where || options.orderBy) { + console.log( + chalk.gray( + ' ⚠️ Note: Filtered/ordered collection group queries may require a Firestore composite index.' + ) + ); + console.log( + chalk.gray( + ' If this query fails with an index error, follow the link in the error' + ) + ); + console.log( + chalk.gray( + ' message to create the required index in Firebase Console.\n' + ) + ); + } let query: admin.firestore.Query< admin.firestore.DocumentData, admin.firestore.DocumentData diff --git a/src/commands/firestore/firestore-query.ts b/src/commands/firestore/firestore-query.ts index 07af35c..27c5440 100644 --- a/src/commands/firestore/firestore-query.ts +++ b/src/commands/firestore/firestore-query.ts @@ -26,7 +26,7 @@ const firestoreQuery = program ) .option( '-g, --collection-group', - 'Query as a collection group - searches all subcollections with this name across the entire database (requires a Firestore index)' + 'Query as a collection group - searches all subcollections with this name across the entire database (filtered/ordered queries may require a Firestore index)' ) .option('--json', 'Output results as JSON') .option('--output ', 'Save JSON output to file') @@ -68,7 +68,7 @@ Examples: Note: Query options (--where, --limit, --order-by) apply to collection queries and document array fields. Field queries (--field) only apply to document queries. -Collection group queries (--collection-group) may require a Firestore composite index - follow +Collection group queries (--collection-group) with filters or ordering may require a Firestore composite index - follow the link in the error message to create it in Firebase Console if needed.` ) .action(async (collection, subcollections, options) => { From c3546f266d8e2462b586fbe0460d200e06818350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Ayhan?= Date: Sat, 7 Mar 2026 17:47:30 +0300 Subject: [PATCH 4/4] =?UTF-8?q?docs:=20update=20firest=C4=B1re=20query=20h?= =?UTF-8?q?elp=20examples?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/firestore/firestore-query.ts | 2 +- src/commands/firestore/firestore-query.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/actions/firestore/firestore-query.ts b/src/actions/firestore/firestore-query.ts index daee0a6..8acac48 100644 --- a/src/actions/firestore/firestore-query.ts +++ b/src/actions/firestore/firestore-query.ts @@ -230,7 +230,7 @@ async function queryDocument( const [filterField, operator, value] = options.where.split(','); if (!filterField || !operator || value === undefined) { throw new Error( - 'Where clause must be in format "field,operator,value" (e.g., "page_type,==,question-page_v1")' + 'Where clause must be in format "field,operator,value" (e.g., "page_type,==,question_1")' ); } diff --git a/src/commands/firestore/firestore-query.ts b/src/commands/firestore/firestore-query.ts index 27c5440..0b7a0f1 100644 --- a/src/commands/firestore/firestore-query.ts +++ b/src/commands/firestore/firestore-query.ts @@ -56,13 +56,13 @@ Examples: $ firebase-tools-cli firestore:query orders --collection-group --order-by "createdAt,desc" --limit 20 Field-specific queries (document queries only): - $ firebase-tools-cli firestore:query mobile_onboardings 1 --field pages + $ firebase-tools-cli firestore:query onboardings v1 --field pages $ firebase-tools-cli firestore:query users user1 --field profile.settings $ firebase-tools-cli firestore:query posts post1 --field metadata.tags.0 Field queries with filtering (array fields only): - $ firebase-tools-cli firestore:query mobile_onboardings 1 --field pages --where "page_type,==,question-page_v1" - $ firebase-tools-cli firestore:query mobile_onboardings 1 --field pages --where "page_type,==,question-page_v1" --order-by "page_order,asc" + $ firebase-tools-cli firestore:query onboardings v1 --field pages --where "page_type,==,question_1" + $ firebase-tools-cli firestore:query onboardings v1 --field pages --where "page_type,==,question_1" --order-by "page_order,asc" $ firebase-tools-cli firestore:query users user1 --field posts --where "published,==,true" --limit 5 $ firebase-tools-cli firestore:query posts post1 --field comments --where "rating,>=,4" --order-by "timestamp,desc"