adonis-mqmodel

MQ-Models is a set of base models for MQ's Team server. MQ-Models runs on **Adonisjs 4**, **lucid-mongo**. It rewrites the relational definitions in models and functions to extend and query the mongoDB more easily. Lucid mongo: https://github.com/duyluong

Usage no npm install needed!

<script type="module">
  import adonisMqmodel from 'https://cdn.skypack.dev/adonis-mqmodel';
</script>

README

Welcome to MQ-Adonisjs-Models!

MQ-Models is a set of base models for MQ's Team server. MQ-Models runs on Adonisjs 4, lucid-mongo. It rewrites the relational definitions in models and functions to extend and query the mongoDB more easily. Lucid mongo: https://github.com/duyluonglc/lucid-mongo

Install

npm install adonis-mqmodel

in Models file: use use('adonis-mqmodel') as BaseModel.

    const Model =  use('adonis-mqmodel')
    class  User  extends  Model {
        .....
    }
```	

in start/app.js add command:
```javascript
...
/*
|--------------------------------------------------------------------------
| Commands
|--------------------------------------------------------------------------
|
| Here you store ace commands for your package
|
*/
const commands = [
  'adonis-mqmodel/Commands/commands.js'
]
....

Using

Relations

This package support relations like lucid-mongo:

  • belongsTo
  • belongsToMany
  • hasMany
  • hasManyThrough
  • hasOne
  • morphMany
  • morphTo
  • morphOne
  • embedsOne
  • embedsMany
  • referMany

Addition relations

Use relationships to declare relationships, which are structured as:

    static get relationships() {
        return {
            <relationName1>:{
                <relatedName1>: [<Model Related 1>, <localField>, <ForeginField>],
                <relatedName2>: [<Model Related 2>, <localField>, <ForeginField>],
            },
            <relationName2>:{
                <relatedName3>: [<Model Related 3>, <localField>, <ForeginField>],
                <relatedName4>: [<Model Related 4>, <localField>, <ForeginField>, <custom params (optional)>],
            },
        }
    }

Relations between tables will be created automatically, but in the case of too complex data, it is necessary to declare custom params to create data constraints. Example:

    const Model =  use('adonis-mqmodel')
    class  User  extends  Model {
        static  get relationships() {
            return {
                hasMany: {
                    tokens: ['App/Models/Token', '_id', 'userId']
                },
                referMany: {
                    roles: ['App/Models/Role', '_id', 'roleIds'],
                    permissions: ['App/Models/Permission', '_id', 'permissionIds', {
            $lookup: {
              from: 'permissions',
              let : {
                localField: `$roles.permisstions`
              },
              pipeline: [
                {$match:{
                  $expr: {$in: ["$_id", "$localField"]}
                }}
              ],
              as: 'permissions'
            }
            }]},
                }
            }
        }
        .....
    }

Schema

Schema is the structure of the database. It is used to query more easily. The library automatically generates schemas or you can create them manually. Automatic creation using command:

adonis mqmodel schema: create

To be able to create automatically, you need to create all the tables and insert into each table at least one record template.

Handmade: Create the folder app / Models / Schemas / In this folder, create the files corresponding to each model. Its format is json. "Field Name": "Data type" For example: User.json

{
    "_id": "objectid",
    "account": "string",
    "name": "string",
    "password": "string",
    "roleIds": "array",
    "permissionIds": "array",
    "created_at": "moment",
    "updated_at": "moment",
    "roles": "function",
    "permissions": "function",
    "tokens": "function"
}

Acceptable data types: string number array object moment objectid string

Query

Same as Lucid-mongo & mquery:

        const users =  await User.all()
        const users =  await User.where('name', 'peter').fetch()
        const users =  await User.where({ name: 'peter' })
      .limit(10).skip(20).fetch()
    
        const users =  await User.where({
          $or: [
            { gender: 'female', age: { $gte: 20 } }, 
            { gender: 'male', age: { $gte: 22 } }
          ]
        }).fetch()
    
        const user =  await User
          .where('name').eq('peter')
          .where('age').gt(18).lte(60)
          .sort('-age')
          .first()
    
        const users =  await User
          .where({ age: { $gte: 18 } })
          .sort({ age: -1 })
          .fetch()
    
        const users =  await User
          .where('age', '>=', 18)
          .fetch()
        
        const users =  await User
          .where('age').gt(18)
          .paginate(2, 100)
        
        const users =  await User.where(function() {
          this.where('age', '>=', 18)
        }).fetch()
    
    // to query geo near you need add 2d or 2dsphere index in migration file
        const images = await Image
          .where(location)
          .near({ center: [1, 1] })
          .maxDistance(5000)
          .fetch()
        
        const images = await Image
          .where(location)
          .near({ center: [1, 1], sphere: true })
          .maxDistance(5000)
          .fetch()
    
    [More Documentation of mquery](https://github.com/aheckmann/mquery)
    
    ### [](https://github.com/duyluonglc/lucid-mongo#aggregation)Aggregation
    
      // count without group by
      const count = await Customer.count()
    
      // count group by `position`
      const count_rows = await Customer
        .where({ invited: { $exist: true } })
        .count('position')
    
      // max age without group by
      const max = await Employee.max('age')
    
      // sum `salary` group by `department_id`
      const total_rows = await Employee
        .where(active, true)
        .sum('salary', 'department_id')
    
      // average group by `department_id` and `role_id`
      const avg_rows = await Employee
        .where(active, true)
        .avg('salary', { department: '$department_id', role: '$role_id' })

Aggregation

MQ-Models hỗ trợ aggregation. sử dụng fetchAggregate() hoặc aggregate([....])

Example:

    const users = await User.with('emails').fetchAggregate()
     const users = await User.with('emails').aggregate([
         $match: {
             username: /ngoc/i
         },
         $unwind: {
             path: 'emails',
             preserveNullAndEmptyArrays: true
         }
    ])
    //or
    const users = await User.with('emails').where({username: "ngoc"}).fetchAggregate()
```	
More: https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/
#### Auto unwind
By default, auto-unwind supports aggragation with dependencies: belongsTo,
  hasOne, embedsOne, morphOne.
You can add more by overriding the autoUnwind function below:
```javascript
    static  get autoUnwind(){
        return [
            "belongsTo",
            "hasOne",
            "embedsOne",
            "morphOne"
        ]
    }

lookup Recursive

Order.query.lookupRecursive({
          '_id': 1,
          'code': 1,
          'customer_name': 1,
          'type': 1,
          'status': 1,
          'OrderDetail': {
            _id: 1,
            quantity: 1,
            Product: {
              _id: 1,
              name: 1
            },
            $match: {
              quantity: {$gte: "4"}
            }
          },
          $match: {
            "OrderDetail._id" : {
              $exists: true
            }
          }
        }).fetchAggregate()

output:

{
    "_id": "5bdc15838270df06b49008f8",
    "code": "123456",
    "customer_name": "日本㈱",
    "type": "0",
    "status": "1",
    "customer_code": "12345",
    "OrderDetail": [
        {
            "_id": "5bdfa2c23829550b884a6679",
            "quantity": "5",
            "Product": {
                "_id": "5bd17ece0762192320a6d634",
                "name": "L金型",
            }
        },
        {
            "_id": "5bdfa2c23829550b884a6672",
            "quantity": "5",
            "Product": {
                "_id": "5bd17ece0762192320a6d634",
                "name": "L金型",
            }
        },
        {
            "_id": "5bdfa2c23829550b884a66fd",
            "quantity": "5",
            "Product": {
                "_id": "5bd17ece0762192320a6d634",
                "name": "L金型",
            }
        },
        {
            "_id": "5bdfa2c23829550b884a6612",
            "quantity": "5",
            "Product": {
                "_id": "5bd17ece0762192320a6d634",
                "name": "L金型",
            }
        }
    ]
}

NgocHip