Prechádzať zdrojové kódy

添加populate关联

lrf 2 rokov pred
rodič
commit
d38c43c86c
2 zmenil súbory, kde vykonal 98 pridanie a 57 odobranie
  1. 25 2
      README.zh_CN.md
  2. 73 55
      lib/service/crud-service.js

+ 25 - 2
README.zh_CN.md

@@ -1,15 +1,38 @@
-# 多租户模式
+# 使用说明
 
-## model配置中
+---
+
+## 多租户模式
+
+### 1.model配置中
 
 >```const schema = new Schema(user, { 'multi-tenancy': true, toJSON: { virtuals: true } });```
 
+---
+
+## 有关populate使用说明
+
+如果使用框架中的populate进行关联查询,ref部分将不再是单纯的表名(模型名,model),而是需要带路径的表名
+>e.g.:目录结构为
+model
+|`__`user
+$~~~~~~$|`__`user.js
+
+在某model的字段关联user时,需要写成: `key: {..., ref: 'User.User', ...}`
+若要获取该关联的属性, 添加 `getProp` 属性 : `key: {..., ref: 'User.User', getProp: ['${prop}','${key}.${prop}'] ...}`
+
+ps:自己写的话,随便
+
+---
+
 ## 中间件说明
 
 ### password
 
 针对以 非login结尾 的 POST 方法的路由,且 request.headers 中 没有 passwordNoDeal 或 passwordNoDeal 为 false 的请求中. 将 body中的password字段 修改为 {secret:password}的形式
 
+---
+
 ## npm 发布相关
 
 ## `npm version patch` 更新版本号

+ 73 - 55
lib/service/crud-service.js

@@ -1,6 +1,6 @@
 'use strict';
 
-const { isString, isArray, cloneDeep, head: getHead, get, omit, last } = require('lodash');
+const _ = require('lodash');
 const { isNullOrUndefined, trimData } = require('naf-core').Util;
 const assert = require('assert');
 const { ObjectId } = require('mongoose').Types;
@@ -125,9 +125,9 @@ class CrudService extends NafService {
     if (_id || id) filter = { _id: ObjectId(_id || id) };
 
     // 处理排序
-    if (sort && isString(sort)) {
+    if (sort && _.isString(sort)) {
       sort = { [sort]: desc ? -1 : 1 };
-    } else if (sort && isArray(sort)) {
+    } else if (sort && _.isArray(sort)) {
       sort = sort.map(f => ({ [f]: desc ? -1 : 1 })).reduce((p, c) => ({ ...p, ...c }), {});
     }
     let res = await this.model.findOne(filter, projection).exec();
@@ -144,16 +144,16 @@ class CrudService extends NafService {
 
   async query(filter, { skip = 0, limit, sort, desc, projection } = {}) {
     // 处理排序
-    if (sort && isString(sort)) {
+    if (sort && _.isString(sort)) {
       sort = { [sort]: desc ? -1 : 1 };
-    } else if (sort && isArray(sort)) {
+    } else if (sort && _.isArray(sort)) {
       sort = sort.map(f => ({ [f]: desc ? -1 : 1 })).reduce((p, c) => ({ ...p, ...c }), {});
     }
-    let condition = cloneDeep(filter);
+    let condition = _.cloneDeep(filter);
     condition = await this.beforeQuery(condition);
     condition = this.dealFilter(condition);
     // 过滤出ref字段
-    const { refMods, populate } = await this.getRefMods();
+    const { refMods, populate } = this.getRefMods();
     // 带ref查询
     let rs = await this.model.find(trimData(condition), projection, { skip, limit, sort }).populate(populate).exec();
     rs = JSON.parse(JSON.stringify(rs));
@@ -162,21 +162,21 @@ class CrudService extends NafService {
       for (const obj of refMods) {
         const { col, prop, type } = obj;
         if (!prop) continue;
-        if (isArray(prop)) {
+        if (_.isArray(prop)) {
           for (const p of prop) {
-            if (type === 'String') i[`${col}_${p}`] = get(i, `${col}.${p}`);
+            if (type === 'String') i[`${col}_${p}`] = _.get(i, `${col}.${p}`);
             if (type === 'Array') {
               const list = [];
-              const oList = get(i, `${col}`);
+              const oList = _.get(i, `${col}`);
               for (const d of oList) {
                 const obj = { _id: d._id };
-                obj[p] = get(d, p);
+                obj[p] = _.get(d, p);
                 list.push(obj);
               }
               i[`${col}_${p}`] = list;
             }
           }
-          i[col] = get(i, `${col}._id`);
+          i[col] = _.get(i, `${col}._id`);
         }
       }
       return i;
@@ -185,39 +185,8 @@ class CrudService extends NafService {
     return rs;
   }
 
-  async getRefMods() {
-    const mod = await this.getModel();
-    const refMods = [];
-    const populate = [];
-    for (const key in mod) {
-      if (!mod[key].ref && !mod[key].refPath) continue;
-      const obj = { col: key, prop: mod[key].getProp, type: mod[key].type.name };
-      if (mod[key].ref) {
-        const ref = mod[key].ref;
-        if (ref.includes('.')) {
-          // 说明是跨数据源
-          const arr = ref.split('.');
-          const conn = this.app.mongooseDB.get(getHead(arr));
-          const refModel = last(arr);
-          const schema = get(this.ctx.model, `${refModel}.schema`);
-          const model = conn.model(refModel, schema);
-          const p = { path: key, model };
-          populate.push(p);
-        } else {
-          const p = { path: key };
-          populate.push(p);
-        }
-      } else if (mod[key].refPath) {
-        const p = { path: key };
-        populate.push(p);
-      }
-      refMods.push(obj);
-    }
-    return { refMods, populate };
-  }
-
   async count(filter) {
-    let condition = cloneDeep(filter);
+    let condition = _.cloneDeep(filter);
     condition = await this.beforeQuery(condition);
     condition = this.dealFilter(condition);
     const count = await this.model.count(condition);
@@ -238,7 +207,8 @@ class CrudService extends NafService {
 
   turnFilter(filter) {
     const str = /^%\S*%$/;
-    let keys = Object.keys(filter);
+    // $是mongodb固定条件,不用处理;大多为手写特殊处理过的条件
+    let keys = Object.keys(filter).filter(f => !f.includes('$'));
     for (const key of keys) {
       const res = key.match(str);
       if (res) {
@@ -248,9 +218,9 @@ class CrudService extends NafService {
       }
     }
     // 再次过滤数据,将数组的数据都变成{$in:value},因为查询变成了聚合查询
-    keys = Object.keys(filter);
+    keys = Object.keys(filter).filter(f => !f.includes('$'));
     for (const key of keys) {
-      if (isArray(filter[key])) {
+      if (_.isArray(filter[key])) {
         filter[key] = { $in: filter[key] };
       } else if (filter[key] === 'true' || filter[key] === 'false') {
         // 布尔类型的值检查,如果是布尔类型,则将字符串转为布尔
@@ -294,13 +264,6 @@ class CrudService extends NafService {
     return filter;
   }
 
-  /**
-   * 获取model的配置
-   */
-  async getModel() {
-    const obj = this.model.prototype.schema.obj;
-    return obj;
-  }
   /**
    * 读取model中不显示的字段
    */
@@ -313,6 +276,62 @@ class CrudService extends NafService {
     }
     if (Object.keys(project).length > 0) return project;
   }
+
+  getRefMods() {
+    // 找到该表的schema(表结构)
+    const mod = this.getSchema();
+    const populate = this.resetPopulate(mod);
+    const refMods = [];
+    for (const key in mod) {
+      if (!mod[key].ref && !mod[key].refPath) continue;
+      const obj = { col: key, prop: mod[key].getProp, type: mod[key].type.name };
+      refMods.push(obj);
+    }
+    return { refMods, populate };
+  }
+
+  // 格式化model路径
+  formatModelPath(str) {
+    let arr = str.split('.');
+    arr = arr.map(i => _.upperFirst(i));
+    const modelPath = arr.join('.');
+    return modelPath;
+  }
+
+  // 获取model的模式
+  getSchema(path) {
+    const model = this.getModel(path);
+    return _.get(model, 'prototype.schema.obj');
+  }
+
+  // 获取model实例
+  getModel(path) {
+    if (!path) return this.model;
+    let model = _.get(this.ctx.model, path);
+    const clients = this.app.mongooseDB.clients;
+    if (clients && !model) {
+      model = _.get(this.ctx.model, `${this.app.config.defaultModule}.${path}`);
+    }
+    return model;
+  }
+  // 针对每个表进行检查
+  resetPopulate(schema) {
+    const arr = [];
+    for (const key in schema) {
+      const e = schema[key];
+      const { ref } = e;
+      if (!ref) continue;
+      const obj = { path: key };
+      const modelPath = this.formatModelPath(ref);
+      const model = this.getModel(modelPath);
+      obj.model = model;
+      const msch = this.getSchema(modelPath);
+      const popu = this.resetPopulate(msch);
+      if (popu.length > 0) obj.populate = popu;
+      arr.push(obj);
+    }
+    return arr;
+  }
 }
 
 // 聚合式查询
@@ -332,5 +351,4 @@ class CrudService extends NafService {
 // }
 // let rs = await this.model.aggregate(pipeline);
 
-
 module.exports.CrudService = CrudService;