如何在过滤器对象中命名相关模型的字段?

时间:2017-07-10 10:11:33

标签: json where-clause loopbackjs

在我的项目中,有两个模型" UserProfile"和" UserAccount"有一种关系,前者"有一个"后来。 .json文件看起来像:

userprofile.json:

{
  "name": "Userprofile",
  "base": "PersistedModel",
  //...
  "properties": {
    "userid": {
      "type": "Number"
    },
    "phoneno": {
      "type": "String"
    }
  },
  //...
  "relations": {
    "userAccounts": {
      "type": "hasOne",
      "model": "UserAccount",
      "foreignKey": "id",
      "options": {
        "validate": true,
        "forceId": false
      }
    }
  }
}

useraccount.json:

{
  "name": "UserAccount",
  "base": "User",
  "idInjection": true,
  "restrictResetPasswordTokenScope": true,
  "emailVerificationRequired": true,
  "properties": {},
  "relations": {}
  //...
}

模型在MariaDB中有相应的表。

现在的任务是" GET" UserProfile,其关键字与UserProfile.phoneno UserAccount.email的任何一个字段匹配(是的,关键点是)。在SQL术语中,即:

SELECT * FROM UserProfile INNER JOIN UserAccount 
ON UserProfile.userid = UserAccount.id
WHERE UserProfile.phoneno LIKE '%keyword%'
OR UserAccount.email LIKE '%keyword%'

它应该是SQL中常见且简单的查询,但在LookBack中似乎变得很困难。我的实现是:

userprofile.js:

'use strict';

module.exports = function (Userprofile) {
  Userprofile.remoteMethod('profileByEmailOrPhoneno', {
    description: '...',
    http: {path:'/profileByEmailOrPhoneno', verb: 'get'},
    accepts: {arg: 'keyword', type: 'string', required: true},
    returns: {arg: 'profile', type: 'array' } 
  })

  Userprofile.profileByEmailOrPhoneno = function (keyword, cb) {
    let filter = {
      fields: {userid: true, nickname: true, phoneno: true},
      include: {
        relation: 'userAccounts',
        scope: {
          fields: {username: true, email: true}
        }
      },
      where: {or: [
        {phoneno: {like: `%${keyword}%`}}, 
        {'userAccount.email': {like: `%${keyword}%`}}
      ]} 
    }

    Userprofile.find(
      filter,
      function (err, records) {
        if (err) console.log(err)
        else cb(null, records)
      }
    )
  }
};

我在StrongLoop API Explorer上测试了它,无论关键字是什么,它总是返回UserProfile中的所有记录。如果标准

{'userAccount.email': {like: `%${keyword}%`}}

删除了代码正常工作。我认为这个标准是错误的,所以LookBack忽略它并评估where部分是真的。我将其修改为:

{'email': {like: `%${keyword}%`}}

它仍然是错误的。

所以,我想知道如何正确命名关系模型的字段(例如,'电子邮件'),或者如何编写正确的过滤器。有人可以帮忙吗?我非常感谢它。 ^^

1 个答案:

答案 0 :(得分:0)

Loopback中的 include 语句是一个left-outer-join,因此查询将始终返回所有Userprofile记录。有些人将拥有带有数组值的userAccounts,其他人则不会。您需要进一步过滤Userprofile记录。

此外,您需要将userAccoutns过滤器放在过滤器的范围语句中:

Userprofile.profileByEmailOrPhoneno = function (keyword, cb) {
  let filter = {
    fields: {userid: true, nickname: true, phoneno: true},
    include: {
      relation: 'userAccounts',
      scope: {
        fields: {username: true, email: true},
        where: {'email':{'like': `%${keyword}%`}} // userAccounts filter goes here
      }
    },
    where: {phoneno: {like: `%${keyword}%`}} 
  }

  Userprofile.find(filter, function (err, records) {
    if (err) console.log(err)
    else {
      // filter the records for those that have userAccounts
      var filteredResults = records.filter(record => 
        record.userAccounts && 
        Array.isArray(record.userAccounts()) && 
        record.userAccounts().length);
      cb(null, filteredResults)
    }
  })
}