{"id":14975546,"url":"https://github.com/0xvoidmain/relax-ql","last_synced_at":"2025-03-29T08:31:56.776Z","repository":{"id":18471236,"uuid":"84390832","full_name":"0xvoidmain/relax-ql","owner":"0xvoidmain","description":"A simple query language for mongoodb. It base on mongoosejs. Everything is too easy to getting done your job. Write LESS, do MORE and Let's RELAX","archived":false,"fork":false,"pushed_at":"2023-11-17T14:02:30.000Z","size":42,"stargazers_count":9,"open_issues_count":15,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-19T13:52:29.019Z","etag":null,"topics":["graphql","mongodb","mongoosejs","query","relax-ql"],"latest_commit_sha":null,"homepage":"","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/0xvoidmain.png","metadata":{"files":{"readme":"README.md","changelog":null,"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}},"created_at":"2017-03-09T02:52:59.000Z","updated_at":"2021-12-08T08:50:52.000Z","dependencies_parsed_at":"2023-11-17T15:58:19.475Z","dependency_job_id":null,"html_url":"https://github.com/0xvoidmain/relax-ql","commit_stats":null,"previous_names":["tunght91/relax-ql"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xvoidmain%2Frelax-ql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xvoidmain%2Frelax-ql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xvoidmain%2Frelax-ql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xvoidmain%2Frelax-ql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/0xvoidmain","download_url":"https://codeload.github.com/0xvoidmain/relax-ql/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246162092,"owners_count":20733351,"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":["graphql","mongodb","mongoosejs","query","relax-ql"],"created_at":"2024-09-24T13:52:11.490Z","updated_at":"2025-03-29T08:31:56.512Z","avatar_url":"https://github.com/0xvoidmain.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# What is relax-ql?\nA simple query language for mongoodb. It base on mongoosejs. Everything is too easy to getting done your job.\nWrite LESS, do MORE and Let's RELAX (after done :v)\n\n# Models\n```javascript\nvar ReviewSchema = Schema({\n  author: ObjectId,\n\tlocalBiz: ObjectId,\n\tpostedTime: Date,\n\tcontent: String,\n\trating: Number,\n\tlikes: [ObjectId]   //Array of users id liked this review\n});\nconst LocalBizSchema = new Schema({\n\tname: String,\n\tcategories: [String],\n\taddress: String,\n\trating: Number\n});\n\nconst UserSchema = new Schema({\n\temail: String,\n\tdisplayName: String\n});\n\nconst BrandSchema = new Schema({\n\tname: String,\n\tlocalBizs: [ObjectId] //Array of localbizs id of this brand\n});\n\nvar Review = mongoose.model('Review', ReviewSchema);\nvar LocalBiz = mongoose.model('LocalBiz', LocalBizSchema);\nvar User = mongoose.model('User', UserSchema);\nvar Brand = mongoose.model('Brand', BrandSchema);\n\nmodule.exports = {\n  Review,\n  LocalBiz,\n  User,\n  Brand\n}\n```\n\n# Setup relax-ql\n```javascript\nvar ql = require('relax-ql');\nql.add({\n  models: require('./db')\n});\n```\n\n# Example 1\nYou want get 10 reviews from database.\n\nWith mongoosejs:\n```javascript\nReview\n  .find()\n  .limit(10)\n  .lean()\n  .exec()\n  .then(reviews =\u003e console.log(reviews));\n```\n\nWith relax-ql:\n```javascript\nql`*: Review().limit(10)`\n  .exec()\n  .then(result =\u003e console.log(result));\n```\n\n# Example 2\nThe code above is a simple query. And now, we will do with a more complex query. We will get 10 reviews from database and each review contain information of reviewer.\n\nWith mongoosejs:\n```javascript\nReview\n  .find()\n  .limit(10)\n  .lean()\n  .exec()\n  .then(reviews =\u003e {\n    return Promise.all(\n      reviews.map(review =\u003e new Promise((resolve, reject) =\u003e {\n        User.findOne({\n          _id: review.author\n        })\n        .lean()\n        .exec()\n        .then(user =\u003e {\n          review.authorDetail = user;\n          resolve(review);\n        })\n        .catch(err =\u003e eject(err))\n      }))\n    )\n  })\n  .then(reviews =\u003e console.log(reviews));\n```\n\nWith relax-ql:\n```javascript\nql`\n  *: Review().limit(10)\n    authorDetail: User[this.author]`\n.exec()\n.then(reviews =\u003e console.log(reviews));\n```\n\n# Example 3\nSelect and projection data\n\nWith mongoosejs:\n```javascript\nReview\n  .find()\n  .limit(10)\n  .lean()\n  .exec()\n  .select({\n    content: true,\n    rating: true,\n    author: true,\n    likes: {\n      $slice: 3\n    }\n  })\n  .then(reviews =\u003e {\n    return Promise.all(\n      reviews.map(review =\u003e new Promise((resolve, reject) =\u003e {\n        User.findOne({\n          _id: review.author\n        })\n        .lean()\n        .exec()\n        .select({\n          displayName: true,\n          email: true\n        })\n        .then(user =\u003e {\n          review.author = user;\n          resolve(review);\n        })\n        .catch(err =\u003e eject(err))\n      }))\n    )\n  })\n  .then(reviews =\u003e console.log(reviews));\n```\n\nWith relax-ql:\n```javascript\nql`\n  *: Review().limit(10)\n    content\n    rating\n    likes(slice: 3)\n    author:= User[this.author]\n      displayName\n      email`\n.exec()\n.then(reviews =\u003e console.log(reviews));\n```\n\n# So, what is relax-ql can do?\n## Begin with Find or FindOne\n\nFind 10 reviews with rating = 5\n```javascript\nql`*: Review(rating == 5).limit(10)`\n.exec()\n.then(reviews =\u003e console.log(reviews));\n```\nor\n```javascript\nql`*: Review.find(rating == 5).limit(10)`\n```\n\nFindOne review with rating \u003e= 3\n```javascript\nql`*: Review[rating == 5]`\n```\nor\n```javascript\nql`*: Review.findOne(rating == 5)`\n```\n\n## Support query selectors\n### Comparison\n```\n== : $eq\n!= : $ne\n\u003c : $lt\n\u003e : $gt\n\u003c= : $lte\n\u003e= : $gte\nIN : $in\nNIN : $nin\nin : $in\nnin : $nin\n```\n\n### Logical\n```\n\u0026\u0026 : $and\n```\n\n### Element\n```\nEXISTS : $exists\nTYPE : $type\nexists : $exists\ntype : $type\n```\n\n### Evaluation\n```\nMOD : $mod\nREGEX : $regex\nTEXT : $text\nWHERE : $where\nmod : $mod\nregex : $regex\ntext : $text\nwhere : $where\n```\n### Array\n```\nALL : $all\nMATCH : $elemMatch\nSIZE: $size\nall : $all\nmatch : $elemMatch\nsize: $size\n```\n\n## Example query selectors\n\n### Example 1\n```\nlikeNumber \u003e= 5 \u0026\u0026 likeNumber \u003c 100 \u0026\u0026 rating IN [2, 3] \u0026\u0026 comments EXISTS true\n```\n\nparse to\n\n```javascript\n{\n  likeNumber: {\n    $gte: 5,\n    $lt: 100\n  },\n  rating: {\n    $in: [2, 3]\n  },\n  comments: {\n    $exists: true\n  }\n}\n```\n\n## How to write a query selector\n\nThe bellow is rules for write query selector.\n\n1. Attribute always is left side of operator and value to compare must be right side of operator\n2. Currently, relax-ql not support OR logical operation. Only use and. But we absolutely write a complex query selector. I will show to you in next session.\n3. relax-ql support some type like: String, Number, Boolean, Array, Object, Regex. Example: \"abc\" or 'abc' is string, [1, 2, 3] is array of number, {a : 1} is an object, true or TRUE or False is booleam type and /abcd/ig is regex type.\n4. Can pass value by params, also pass a query selector by params. I'll show to you in next session.\n\n## Advance Find and FindOne\n### Find with complex query selector\n1.\n```javascript\nql`reviews: Review(likeNumber \u003e= 5 \u0026\u0026 likeNumber \u003c 100 \u0026\u0026 rating IN [2, 3] \u0026\u0026 comments EXISTS true)`\n```\n2.\n```javascript\nql`reviews: Review(${{\n    $or: [{\n      likeNumber: 5\n    }, {\n      likeNumber: 4\n    }]\n  }})`\n```\nor use param\n```javascript\nvar reviewQuery = {\n  $or: [{\n    likeNumber: 5\n  }, {\n    likeNumber: 4\n  }],\n  rating: {\n    $in: [1, 2]\n  },\n  comments: {\n    $all: [\n      { \"$elemMatch\" : { likeNumber: { $gt: 50, $lt: 100} } },\n      { \"$elemMatch\" : { content : { $regex: /abcd/i } } }\n    ]\n  }\n}\nql`reviews: Review(${reviewQuery})`\n```\n\n### Find with options\nrelax-ql support limit, skip, sort (ASC, DESC)\n```javascript\nql`reviews: Review(likeNumber \u003e= 5).limit(10).skip(10).DESC('rating').ASC('createdAt')`\n```\n\nNote: Sepecial support *unlean* optional. Because the query default call .lean() function. When we use unlean option, the query will not call .lean(). It very usefull when you defined some virtual atributes. Example:\n\nModel:\n```javascript\nvar PersonSchema = new Schema({\n  name: {\n    first: String,\n    last: String\n  }\n}, {\n  toObject: { virtuals: true },\n  toJSON: { virtuals: true }\n});\nPersonSchema\n  .virtual('displayName')\n  .get(function () {\n    return this.name.first + ' ' + this.name.last;\n  });\n\nvar Person = mongoose.model('Person', PersonSchema);\n```\nDon't use unlean()\n```javascript\nql`*: Person[]`\n.exec()\n.then(p =\u003e console.log(p));\n// display on screen\n/*\n{\n  name: {\n    first: 'abc',\n    last: 'def'\n  }\n}\n*/\n```\n\nUse unlean() optional\n```javascript\nql`*: Person[].unlean()`\n.exec()\n.then(p =\u003e console.log(p));\n// display on screen\n/*\n{\n  name: {\n    first: 'abc',\n    last: 'def'\n  },\n  displayName: 'abc def'\n}\n*/\n```\n\n## Selection and projection\n\n### Selection\n```javascript\nql`\n  reviews: Review(likeNumber \u003e= 5)\n    comments\n    content\n    rating\n`\n```\nor\n```javascript\nql`\n  status: Status[]\n    content\n    user\n      name\n      gender\n\n`\n```\nIt'll be\n```javascript\nStatus.findOne()\n  .select({\n    content: true,\n    user: true,\n    'user.name': true,\n    'user.gender': true\n  })\n```\n\n### Projection\nSupport\n```\nslice : $slice\nSLICE : $slice\nmatch : $elemMatch\nMATCH : $elemMatch\nmeta : $meta\nMETA : $meta\n```\nExample:\n```javascript\nql`\n  status: Status[]\n    content\n    likes(3)\n    comments(slice: 3)\n`\n```\n=\u003e\n```javascript\nStatus.findOne()\n  .select({\n    content: true,\n    'likes.$': 3,\n    comments: {\n      $slice: 3\n    }\n  })\n```\n\n## Nested query\n\nExample:\n```javascript\nql`\n  reviews: Review(rating \u003e= 3).limit(5)\n    author\n    authorDetail: User[this.author]\n      displayName\n    localBiz:= LocalBiz[this.localBiz]\n      name\n      address\n    likes\n      *: User[this.$value]\n        displayName\n    relatedReviews: Review(localBiz == this.localBiz).limit(3)\n      content\n      author:= User[this.author]\n        displayName\n`\n```\n\n### Keyword:\n- *this*: The pointer to parent\n- *this.$value*: The value of parent\n- := is select this attribute and result of query will overide to old value.\n- '*' is result of child query will overide to parent value\n\n### How to access data of parent\nCan you see the format of relax-ql like this:\n```javascript\nql`\n  key_name: Model.function(query_selector).optional().optional()\n    attr_selected\n    attr_selected\n    key_name: Model.function(query_selector).optional().optional()\n      attr_selected\n      attr_selected\n\n    attr_selected:= Model.function(query_selector).optional().optional()\n      attr_selected\n        key_name: Model.function(query_selector).optional().optional()\n          attr_selected\n          attr_selected\n    attr_selected\n      *: Model.function(query_selector).optional().optional()\n        attr_selected\n        attr_selected\n\n`\n```\nWe have two way to access to parent data.\n1. Use *this*\n- It will access to nearest parent data\n2. Use key_name\n- It will access to first parent match with key_name\n\n## Roadmap\n\n- Support all logical: AND, OR, NOT\n- Optimize query findOne\n- Fix projection: likes({$slice: 3})","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0xvoidmain%2Frelax-ql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F0xvoidmain%2Frelax-ql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0xvoidmain%2Frelax-ql/lists"}