{"id":18218884,"url":"https://github.com/mobakour/potatodb","last_synced_at":"2026-03-06T15:31:27.614Z","repository":{"id":238215297,"uuid":"494634070","full_name":"MoBakour/potatodb","owner":"MoBakour","description":"A nodejs filesystem-based json database system","archived":false,"fork":false,"pushed_at":"2024-07-04T08:50:44.000Z","size":150,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-28T23:39:49.908Z","etag":null,"topics":["database","database-management","library","nosql","nosql-database","npm","npm-module","npm-package","package"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/potatodb","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MoBakour.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-20T23:43:34.000Z","updated_at":"2024-11-13T13:55:57.000Z","dependencies_parsed_at":"2024-05-16T14:30:30.790Z","dependency_job_id":"6a5cf3e0-ad4c-4fde-8d3c-ee7fe1f1c065","html_url":"https://github.com/MoBakour/potatodb","commit_stats":{"total_commits":44,"total_committers":2,"mean_commits":22.0,"dds":0.4772727272727273,"last_synced_commit":"19f066fef234051e3a8e8de5201167329f7fca21"},"previous_names":["swordaxsy/potatodb","mohbakour/potatodb","mobakour/potatodb"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MoBakour%2Fpotatodb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MoBakour%2Fpotatodb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MoBakour%2Fpotatodb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MoBakour%2Fpotatodb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MoBakour","download_url":"https://codeload.github.com/MoBakour/potatodb/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241533638,"owners_count":19977825,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","database-management","library","nosql","nosql-database","npm","npm-module","npm-package","package"],"created_at":"2024-11-03T18:05:02.303Z","updated_at":"2026-03-06T15:31:27.567Z","avatar_url":"https://github.com/MoBakour.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PotatoDB\r\n\r\n\u003cp align=\"center\"\u003e\r\n\t\u003cimg width=\"100\" src=\"./logo.png\"\u003e\r\n\t\u003cbr\u003e\r\n\tA nodejs filesystem json database system.\r\n\t\u003cbr\u003e\r\n\tBy \u003ca href=\"https://linkedin.com/in/mobakour\"\u003eMoBakour\u003c/a\u003e\r\n\u003c/p\u003e\r\n\r\n## About\r\n\r\nPotatoDB is a nodejs filesystem json database system that can be used to store and manage data in JSON format in the local filesystem of servers running in the Node.js environment.\r\n\r\n## Features\r\n\r\n1. Easy and simple to use and setup\r\n2. Wide range of control over data\r\n3. Flexibility of querying and updating data\r\n\r\n## How it works\r\n\r\nPotatoDB creates a main databases directory. Every newly created database will result in creating a new directory inside the main databases directory. Every newly created farm (collection in NoSQL or table in SQL) will result in creating a new JSON file inside the relevant database directory. The JSON file will contain an array of objects, and every object of these objects represents a single potato (document in NoSQL or record in SQL).\r\n\r\n## Installation\r\n\r\n```\r\nnpm install potatodb\r\n```\r\n\r\n## Usage\r\n\r\n#### Require\r\n\r\nAfter installing PotatoDB via npm, require `setRoot` and `createDatabase` methods from the library.\r\n\r\n```js\r\nconst { setRoot, createDatabase } = require(\"potatodb\");\r\n```\r\n\r\nor with ES6 import statement\r\n\r\n```js\r\nimport { setRoot, createDatabase } from \"potatodb\";\r\n```\r\n\r\n#### setRoot\r\n\r\nThe `setRoot()` method is used to define the location and the name of the databases directory, which will later host the databases. The method takes two arguments: first is the directory name `__dirname`, and second is the desired name of the databases directory (defaults to \"databases\").\r\n\r\n```js\r\nsetRoot(__dirname, \"databases\");\r\n```\r\n\r\n#### createDatabase\r\n\r\nThe `createDatabase()` method creates a database inside the databases directory, where farms (collections) will be contained. PotatoDB allows you to have multiple databases at the same time, all stored inside the databases directory. The `createDatabase()` method takes two arguments: first is the name of the database, and second is a boolean that specifies whether the database should be cleared out and rewritten whenever the server restarts or not (defaults to `false`).\r\n\r\n```js\r\nconst DB = createDatabase(\"MyDatabase\", false);\r\n```\r\n\r\n#### DB.dropDatabase\r\n\r\nThe `dropDatabase()` method is a database method returned from the `createDatabase()` method, it allows you to entirely drop/delete the database.\r\n\r\n```js\r\nDB.dropDatabase();\r\n```\r\n\r\n#### DB.createFarm\r\n\r\nThe `createFarm()` method is a database method returned from the `createDatabase()` method, it allows you to create farms inside the database directory. Farms in PotatoDB are like collections in NoSQL databases or tables in SQL databases. This method takes two arguments: first is the name of the farm, and second is an options object.\r\n\r\n```js\r\nconst Farm = DB.createFarm(\"Farm\", {\r\n\tidentifications: true,\r\n\ttimestamps: true,\r\n});\r\n```\r\n\r\nAvailable options:\r\n\r\n-   `identifications`\r\n    Speicifes whether the potatoes (documents in NoSQL or records in SQL) inside the farm should be stamped with identification strings or not. (defaults to true)\r\n-   `timestamps`\r\n    Specifies whether the potatoes (document in NoSQL or records in SQL) inside the farm should be stamped with timestamps (createdAt and updatedAt). Timestamps contain numerical timestamps that point to the time when the potato object was first created and lastly updated. (defaults to true)\r\n\r\n#### Farm.countPotatoes\r\n\r\nThe `countPotatoes()` method is an asynchronous farm method returned from the `DB.createFarm()` method, it returns the precise number of potato objects in the farm.\r\n\r\n```js\r\nawait Farm.countPotatoes();\r\n```\r\n\r\n#### Farm.dropFarm\r\n\r\nThe `dropFarm()` method is a farm method returned from the `DB.createFarm()` method, it allows you to entirely drop/delete the farm from the database.\r\n\r\n```js\r\nFarm.dropFarm();\r\n```\r\n\r\n#### Farm.insertOne\r\n\r\nThe `insertOne()` method is a farm method used to insert a single potato into the farm. The method takes a single potato object as an argument, and returns the inserted object.\r\nIf identifications and timestamps were set on, then the returned potato object will include them.\r\n\r\n```js\r\nawait Farm.insertOne({ name: \"Swordax\", age: 1, isHuman: true });\r\n```\r\n\r\n#### Farm.insertMany\r\n\r\nThe `insertMany()` method is a farm method used to insert multiple potatoes into the farm. The method takes a single array of potato objects as an argument, and returns an array of the inserted objects.\r\nIf identifications and timestamps were set on, then the returned potato objects will include them.\r\n\r\n```js\r\nawait Farm.insertMany([\r\n\t{\r\n\t\tname: \"Vazox\",\r\n\t\tage: 2,\r\n\t\tisHuman: false,\r\n\t},\r\n\t{\r\n\t\tname: \"Alxa\",\r\n\t\tage: 3,\r\n\t\tisHuman: true,\r\n\t},\r\n]);\r\n```\r\n\r\n#### Farm.findOne\r\n\r\nThe `findOne()` method is a farm method used to find a single potato and return it. The method takes two arguments: first is a query object or a test function, and second is an options object. Both arguments are optional.\r\nIf no arguments were provided, or if an empty query object was provided, then the method would return the first potato object it would encounter.\r\n\r\n```js\r\nconst byName = await Farm.findOne({ name: \"Swordax\" });\r\nconst byNameAndAge = await Farm.findOne({ name: \"Alxa\", age: 3 });\r\n```\r\n\r\n#### Farm.findMany\r\n\r\nThe `findMany()` method is a farm method used to find multiple potatoes and return them as an array. The method takes two arguments: first is a query object or a test function, and second is an options object. Both arguments are optional.\r\nIf no arguments were provided, or if an empty query object was provided, then the method would return all potatoes from the farm.\r\n\r\n```js\r\nconst eighteen = await Farm.findMany({ age: 18 });\r\nconst eighteenOrOlder = await Farm.findMany((potato) =\u003e potato.age \u003e= 18);\r\n```\r\n\r\n#### Find Methods Options\r\n\r\nBoth `findOne()` and `findMany()` methods could take a second options object.\r\n\r\nAvailable options:\r\n\r\n-   `limit` : (number) Specifies the maximum number of potatoes to return.\r\n-   `skip` : (number) Specifies the number of potatoes to skip before starting the search.\r\n-   `recent`: (boolean) Specifies whether priority of search should be to recent potatoes. By default, data is traversed oldest to recent.\r\n-   `sort`: (object) An object that specifies the field to sort based on, and the value of that field would specify the order of sorting (positive number for ascending, negative number for descending).\r\n-   `project`: (object) An object that specifies fields to include/exclude from returned result.\r\n\r\nlimit and sort options would make sense to be used with the `findMany()` method.\r\n\r\nExample with options:\r\n\r\n```js\r\nconst data = await UsersFarm.findMany(\r\n\t{},\r\n\t{\r\n\t\trecent: true, // begin searching with most recent data\r\n\t\tlimit: 10, // return maximum of 10 results\r\n\t\tskip: 5, // skip 5 potatoes before beginning the search\r\n\t\tsort: {\r\n\t\t\tage: 1, // sort according to the age field in an ascending order\r\n\t\t},\r\n\t\tproject: {\r\n\t\t\tpassword: 0, // 0 means exclude\r\n\t\t\tsensitiveInformation: 0,\r\n\t\t},\r\n\t}\r\n);\r\n```\r\n\r\n#### Farm.updateOne\r\n\r\nThe `updateOne()` method is a farm method used to update a single potato. The method takes three arguments: first is a query object or a test function, second is an updates object or an update function, and third is an options object.\r\n\r\n```js\r\nawait Farm.updateOne({ name: \"Swordax\" }, { age: 2 }, { updated: true });\r\n```\r\n\r\n#### Farm.updateMany\r\n\r\nThe `updateMany()` method is a farm method used to update mulitple potatoes. The method takes three arguments: first is a query object or a test function, second is an updates object or an update function, and third is an options object.\r\n\r\n```js\r\nawait Farm.updateMany((potato) =\u003e potato.age \u003e= 18, { authorized: false });\r\n```\r\n\r\nIn the above example, the `updateMany()` method took a query test function instead of a query object. The query function filters for potatoes which have the age property greater than or equal to 18.\r\n\r\n#### Update Methods Options\r\n\r\nBoth `updateOne()` and `updateMany()` methods could take a third options object.\r\n\r\nAvailable options:\r\n\r\n-   `updated`: (boolean) Specifies whether the returned result is the post-update or the pre-update version (defaults to true which returns the updated data).\r\n-   `project`: (object) An object that specifies fields to include/exclude from returned result.\r\n\r\n#### Farm.deleteOne\r\n\r\nThe `deleteOne()` method is a farm method used to delete a single potato. The method takes two arguments: first is a query object or a test function, second is an options object. The method returns the deleted potato object.\r\n\r\n```js\r\nawait Farm.deleteOne({ name: \"Alxa\" });\r\nawait Farm.deleteOne((potato) =\u003e potato.name === \"Vazox\");\r\n```\r\n\r\n#### Farm.deleteMany\r\n\r\nThe `deleteMany()` method is a farm method used to delete multiple potatoes. The method takes two arguments: first is a query object or a test function, second is an options object. The method returns an array of the deleted potato objects.\r\n\r\n```js\r\nawait Farm.deleteMany({ age: 0 });\r\nawait Farm.deleteMany((potato) =\u003e potato.age \u003c 18);\r\n```\r\n\r\n#### Delete Methods Options\r\n\r\nBoth `deleteOne()` and `deleteMany()` methods could take a second options object.\r\n\r\nAvailable options:\r\n\r\n-   `project`: (object) An object that specifies fields to include/exclude from returned result.\r\n\r\n#### Principles of Querying with PotatoDB\r\n\r\nFinding, updating, and deleteing methods of PotatoDB farms all require querying to select potatoes to return or apply changes on. Querying with PotatoDB can be done in two ways: First is object querying by providing a query object. Second is functional querying by providing a test function to be used in querying.\r\n\r\n-   A query object that selects potatoes with a username of \"Swordax\": `{ username: \"Swordax\" }`\r\n-   A query object that selects potatoes with an age of 18: `{ age: 18 }`\r\n-   A query object that selects potatoes with an isMarried property set to true: `{ isMarried: true }`\r\n\r\nYou can query nested properties by using string paths in the query object, nested property keys should be separated with dots.\r\n\r\nThe following example queries users that have the nested `building` field set to \"Uptown Building\" in a dataset that has the following signature:\r\n\r\n```js\r\n{\r\n    name: string,\r\n    age: number,\r\n    country: {\r\n        city: {\r\n            street: {\r\n                building: string\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n```js\r\nconst data = await Users.findMany({\r\n\t\"country.city.street.building\": \"Uptown Building\",\r\n});\r\n```\r\n\r\nThe second way of querying data with PotatoDB is functional querying by using custom filtering test functions. You can design your own test function to be used in querying data instead of a limited query object. The test function takes a potato as an argument and it should return true or false depending on whether the argument passes the test or not.\r\n\r\nThe following example queries users that have \"Arabic\" and \"English\" languages listed in their `languages` field:\r\n\r\n```js\r\nconst data = await Users.findOne((user) =\u003e {\r\n\treturn (\r\n\t\tuser.languages.includes(\"English\") \u0026\u0026 user.languages.includes(\"Arabic\")\r\n\t);\r\n});\r\n```\r\n\r\n#### Query Operators\r\n\r\nPotatoDB provides query operators that can be used in query objects when querying data. Query operators can help you build flexible reachy query objects instead of having to build a custom test function.\r\n\r\nThe following example uses two of the query operators (`$gte` and `$lt`) to select users that are more than or equal to eighteen years old, and those who are less than eighteen years old:\r\n\r\n```js\r\nconst eighteenOrOlder = await Users.findMany({ age: { $gte: 18 } });\r\nconst underEighteen = await Users.findMany({ age: { $lt: 18 } });\r\n```\r\n\r\n##### Comparison Query Operators\r\n\r\n| Operator | JS Equivalent | Function                                 |\r\n| -------- | ------------- | ---------------------------------------- |\r\n| $gt      | \u003e             | Greater than                             |\r\n| $gte     | \u003e=            | Greater than or equal to                 |\r\n| $lt      | \u003c             | Less than                                |\r\n| $lte     | \u003c=            | Less than or equal to                    |\r\n| $eq      | ===           | Equal to                                 |\r\n| $eqv     | ==            | Equal to value (regardless of data type) |\r\n| $neq     | !==           | Not equal to                             |\r\n| $neqv    | !=            | Not equal to (regardless of data type)   |\r\n\r\n##### Logical Query Operators\r\n\r\n| Operator | JS Equivalent                        | Function               |\r\n| -------- | ------------------------------------ | ---------------------- |\r\n| $and     | \u0026\u0026                                   | All queries must pass  |\r\n| $or      | \\|\\|                                 | Some queries must pass |\r\n| $nor     | queries.every(query =\u003e !test(query)) | No queries must pass   |\r\n\r\n`$and`:\r\n\r\n```js\r\n// both provided queries should pass to select the potato object\r\nconst users = await Users.findMany({\r\n\t$and: [{ authenticated: true }, { verified: true }],\r\n});\r\n\r\n// the above is equivalent to this:\r\nconst users = await Users.findMany({\r\n\tauthenticated: true,\r\n\tverified: true,\r\n});\r\n```\r\n\r\nthe `$and` operator may seem to be useless at first, as the query can be done without it. But it's strength comes with nesting logical operators to make more powerful queries.\r\n\r\n`$or`:\r\n\r\n```js\r\n// at least one of the provided queries should pass to select the potato object\r\nconst users = await Users.findMany({\r\n\t$or: [{ name: \"Swordax\" }, { name: \"Vazox\" }],\r\n});\r\n```\r\n\r\n`$nor`:\r\n\r\n```js\r\n// none of the provided queries should pass to select the potato object\r\nconst users = await Users.findMany({\r\n\t$nor: [{ deactivated: true }, { blocked: true }],\r\n});\r\n```\r\n\r\nYou could nest logical operators to create powerful queries:\r\n\r\n```js\r\nconst users = await Users.findMany({\r\n\t$or: [\r\n\t\t{ $and: [queryObject_1, queryObject_2] },\r\n\t\t{ $and: [queryObject_3, queryObject_4] },\r\n\t\t{ $nor: [queryObject_5, queryObject_6] },\r\n\t],\r\n});\r\n```\r\n\r\n##### Array Query Operators\r\n\r\nArray query operators (\\$in, \\$nin, \\$all, and \\$elemMatch) can be used in different scenarios.\r\n\r\nGiven dataset with the following signature:\r\n\r\n```js\r\n{\r\n    name: string,\r\n    age: number,\r\n    hobbies: string[],\r\n    classes: [{\r\n        subject: string,\r\n        gpa: number\r\n    }]\r\n}\r\n```\r\n\r\n`$in`:\r\n\r\n```js\r\n// gets users that have \"Coding\" inside their hobbies array\r\nawait Users.findMany({ hobbies: { $in: \"Coding\" } });\r\n\r\n// gets users that are from the ages, 19, 20, and 21\r\nawait Users.findMany({ age: { $in: [19, 20, 21] } });\r\n\r\n// gets users that have either \"Coding\" or \"Swimming\" inside their hobbies array\r\nawait Users.findMany({ hobbies: { $in: [\"Coding\", \"Swimming\"] } });\r\n```\r\n\r\n`$nin`:\r\n\r\n```js\r\n// gets users that DO NOT have \"Coding\" inside their hobbies array\r\nawait Users.findMany({ hobbies: { $nin: \"Coding\" } });\r\n\r\n// gets users that are NOT from the ages, 19, 20, and 21\r\nawait Users.findMany({ age: { $nin: [19, 20, 21] } });\r\n\r\n// gets users that DO NOT have \"Coding\" and \"Swimming\" inside their hobbies array\r\nawait Users.findMany({ hobbies: { $nin: [\"Coding\", \"Swimming\"] } });\r\n```\r\n\r\n`$all`:\r\n\r\n```js\r\n// gets users that have both \"Coding\" and \"Swimming\" inside their hobbies array\r\nawait Users.findMany({ hobbies: { $all: [\"Coding\", \"Swimming\"] } });\r\n```\r\n\r\n`$elemMatch`:\r\n\r\n```js\r\n// gets users that have the exact subdocument {subject:\"Programming\", gpa:4}\r\n// inside their classes array field\r\nawait Users.findMany({\r\n\tclasses: { $elemMatch: { subject: \"Programming\", gpa: 4 } },\r\n});\r\n```\r\n\r\n#### Principles of Updating with PotatoDB\r\n\r\nUpdating PotatoDB data can be done in two ways, either by providing an updates object, or by providing an updating function.\r\n\r\nAn updates object can be given new values to fields, fields previous values will be overwritten with the new given values. If fields don't exist, they will be created. Multiple fields can be updated at the same time by providing multiple key:value pairs in the updates object.\r\n\r\n```js\r\nawait Users.updateOne({ name: \"Swordax\" }, { age: 2 });\r\nawait Users.updateOne({ name: \"Alxa\" }, { age: 0, isHuman: true });\r\n```\r\n\r\nUpdating nested properties can be done by accessing these nested fields thorugh a string path in the update object. Key names should be separated with dots.\r\n\r\nThe following example access the `height` nested property and updates it's value:\r\n\r\n```js\r\nawait Users.updateOne(\r\n\t{ name: \"Swordax\" },\r\n\t{ \"physicalTraits.body.height\": 184 }\r\n);\r\n```\r\n\r\nAnother way that can be used to update potatoes is update functions. Update functions are custom functions that can be designed to update the potatoes in any way you desire. Update functions give you more flexibility in updating potatoes rather than limiting the possiblities with update objects.\r\n\r\n```js\r\nawait Users.updateOne({ username: \"Swordax\" }, (user) =\u003e {\r\n\tuser.token = Math.floor(Math.random() * 11);\r\n});\r\n```\r\n\r\n#### Update Operators\r\n\r\nPotatoDB provides update operators that can be used inside update objects to give you more flexibility when updating fields. Update operators can give you shorthands to doing things you couldn't do unless you designed your own custom update function.\r\n\r\nThe following example uses the `$push` operator to push \"Arabic\" language into the languages array field:\r\n\r\n```js\r\nawait Users.updateMany(\r\n\t{ nationality: \"Syria\" },\r\n\t{ $push: { languages: \"Arabic\" } }\r\n);\r\n```\r\n\r\nYou could also push to multiple array fields:\r\n\r\n```js\r\nawait Users.updateMany(\r\n\t{ nationality: \"Syria\" },\r\n\t{\r\n\t\t$push: {\r\n\t\t\tlanguages: \"Arabic\",\r\n\t\t\thobbies: \"Dabka Dance\",\r\n\t\t},\r\n\t}\r\n);\r\n```\r\n\r\nYou could use multiple update operators at the same time:\r\n\r\n```js\r\nawait Users.updateMany(\r\n\t{ nationality: \"Syria\" },\r\n\t{\r\n\t\t$push: {\r\n\t\t\tlanguages: \"Arabic\",\r\n\t\t},\r\n\t\t$inc: {\r\n\t\t\tage: 1,\r\n\t\t},\r\n\t}\r\n);\r\n```\r\n\r\n##### Update Operators:\r\n\r\n| Operator  | JS Equivalent                                           | Function                                                                  |\r\n| --------- | ------------------------------------------------------- | ------------------------------------------------------------------------- |\r\n| $inc      | += -=                                                   | Increments/Decrements field by the given value                            |\r\n| $push     | Array.prototype.push()                                  | Pushes a value into an array field                                        |\r\n| $addToSet | Set.prototype.add()                                     | Pushes a value into an array field only if it doesn't already exist in it |\r\n| $pull     |                                                         | Removes all occurrences of a value from an array                          |\r\n| $concat   | Array.prototype.concat() \u003cbr\u003e String.prototype.concat() | Concatenates two arrays/strings together                                  |\r\n\r\n#### Projection\r\n\r\nPotatoDB allows you to perform projection to your query and operations results. Projecting is selecting what fields to include/exclude in the returned result from the operation method. Projection option is available for all find, update, and delete methods in their options object. The option is called `project` and it takes a projection object.\r\n\r\nA projection object takes field names as keys, and zeros or ones as values. Fields flagged with 0 will be excluded while the rest will be included. Fields flagged with 1 will be included while the rest will be excluded. Note that you can't flag fields with zeros and ones at the same time in the same projection object, it's either zeros or ones.\r\n\r\n```js\r\nconst users_with_ids_and_names_and_ages = await Users.findMany(\r\n\t{},\r\n\t{\r\n\t\tproject: {\r\n\t\t\t_id: 1, // will include _id field in results\r\n\t\t\tname: 1, // will include name field in results\r\n\t\t\tage: 1, // will include age field in results\r\n\t\t}, // all other fields will be excluded from the results\r\n\t}\r\n);\r\n\r\nconst users_without_timestamps = await Users.findMany(\r\n\t{},\r\n\t{\r\n\t\tproject: {\r\n\t\t\tcreatedAt: 0, // will exclude createdAt field in results\r\n\t\t\tupdatedAt: 0, // will exclude updatedAt field in results\r\n\t\t},\r\n\t} // all other fields will be included in the results\r\n);\r\n```\r\n\r\n#### Full Example\r\n\r\nThe following code demonstrates the creation of an API that communicates with a PotatoDB database system, integrated with express.js\r\n\r\n```js\r\nconst express = require(\"express\");\r\nconst { setRoot, createDatabase } = require(\"potatodb\");\r\n\r\nconst app = express();\r\n\r\n// configure express app\r\napp.use(express.static(\"public\"));\r\napp.use(express.urlencoded({ extended: true }));\r\napp.use(express.json());\r\n\r\n// set potatodb root\r\nsetRoot(__dirname, \"databases\");\r\n\r\n// create project database and users farm\r\nlet DB, Users;\r\n(async () =\u003e {\r\n\tDB = await createDatabase(\"DB\", false);\r\n\tUsers = await DB.createFarm(\"Users\", {\r\n\t\tidentifications: true,\r\n\t\ttimestamps: true,\r\n\t});\r\n\r\n\t// listen to server requests\r\n\tapp.listen(3000, () =\u003e {\r\n\t\tconsole.log(\"Server running on port 3000\");\r\n\t});\r\n})();\r\n\r\n// create user\r\napp.post(\"/create-user\", async (req, res) =\u003e {\r\n\ttry {\r\n\t\tconst user = await Users.insertOne(req.body);\r\n\t\tres.status(200).json({ success: true, userId: user._id });\r\n\t} catch (err) {\r\n\t\tconsole.log(err);\r\n\t\tres.status(400).json({ success: false, error: err.message });\r\n\t}\r\n});\r\n\r\n// get user\r\napp.get(\"/get-user\", async (req, res) =\u003e {\r\n\ttry {\r\n\t\tconst user = await Users.findOne({ username: req.body.username });\r\n\t\tres.status(200).json({ success: true, user });\r\n\t} catch (err) {\r\n\t\tconsole.log(err);\r\n\t\tres.status(400).json({ success: false, error: err.message });\r\n\t}\r\n});\r\n\r\n// get users (implementing pagination)\r\napp.get(\"/get-users/:pageNumber\", async (req, res) =\u003e {\r\n\tconst resultsPerPage = 10;\r\n\r\n\ttry {\r\n\t\t/*\r\n            1- implement pagination using skip and limit options\r\n            2- show most recent data first\r\n            3- sort data according to \"user.personalInformation.age\" field in ascending order\r\n        */\r\n\r\n\t\tconst users = await Users.findMany(\r\n\t\t\t{},\r\n\t\t\t{\r\n\t\t\t\tskip: resultsPerPage * (req.params.pageNumber - 1),\r\n\t\t\t\tlimit: resultsPerPage,\r\n\t\t\t\trecent: true,\r\n\t\t\t\tsort: {\r\n\t\t\t\t\t\"personalInformation.age\": 1,\r\n\t\t\t\t},\r\n\t\t\t}\r\n\t\t);\r\n\r\n\t\tres.status(200).json({ success: true, users });\r\n\t} catch (err) {\r\n\t\tconsole.log(err);\r\n\t\tres.status(400).json({ success: false, error: err.message });\r\n\t}\r\n});\r\n\r\n// update username\r\napp.patch(\"/update-username\", async (req, res) =\u003e {\r\n\ttry {\r\n\t\tconst updatedUser = await User.updateOne(\r\n\t\t\t{\r\n\t\t\t\tusername: req.body.username,\r\n\t\t\t},\r\n\t\t\t{\r\n\t\t\t\tusername: req.body.newUsername,\r\n\t\t\t},\r\n\t\t\ttrue // get post-updated user object\r\n\t\t);\r\n\r\n\t\tres.status(200).json({ success: true, updatedUser });\r\n\t} catch (err) {\r\n\t\tconsole.log(err);\r\n\t\tres.status(400).json({ success: false, error: err.message });\r\n\t}\r\n});\r\n\r\n// delete user\r\napp.delete(\"/delete-user/:userId\", async (req, res) =\u003e {\r\n\ttry {\r\n\t\tconst deletedUser = await User.deleteOne({ _id: req.params.userId });\r\n\t\tres.status(200).json({ success: true, deletedUser });\r\n\t} catch (err) {\r\n\t\tconsole.log(err);\r\n\t\tres.status(400).json({ success: false, error: err.message });\r\n\t}\r\n});\r\n```\r\n\r\n## Contact\r\n\r\nMy Contacts:\r\n\r\n-   email: mo.bakour@outlook.com\r\n-   linkedin: https://linkedin.com/in/mobakour\r\n-   github: https://github.com/MoBakour\r\n-   linktr.ee: https://linktr.ee/swordax\r\n-   discord: https://discord.com/users/465453058667839499/\r\n-   discord username: swordax\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmobakour%2Fpotatodb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmobakour%2Fpotatodb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmobakour%2Fpotatodb/lists"}