alafafa
alafafa
  • 发布:2024-05-23 12:35
  • 更新:2024-05-23 12:53
  • 阅读:108

如何让副表中的内容作为主表中的一个数组型虚拟字段并实现一对多的关系?

分类:uniCloud

需求描述:存在主表 articles 和副表 comment,想让 comments 表中的内容在 article 表检索时自动变为它的一个 comments 字段

目前如果是主表中存在一个指定关联关系的字段并将其 foreignKey 指向了副表的 _id 是可以实现主表检索时将副表内容作为它的一个字段的,但这往往是一对一的,因为 foreignKey 用的是副表的 _id 也就意味着只能一对一,无法实现一对多,有没有比较好的让副表中的内容作为主表中的一个数组型虚拟字段的一对多的主副表关联查询方案呢?

2024-05-23 12:35 负责人:无 分享
已邀请:
alafafa

alafafa (作者)

先自问自答一下抛砖引玉,期待官方工作人员或各路大神能给出更好的答案


目前有实现一对多的联表查询方案吗?

目前唯一能直接实现的一对多方案就是不在主表中指定关联关系,而是在副表中指定关联关系,比如在副表中增加一个字段:article_id,它的 foreignKey 是 articles._id,但这无法实现检索主表时将副表内容自动变为主表中的一个字段,执行联表查询
时副表中的内容被蛋疼的挂在了主表的 _id 下面,_id 由原来的一个24字符的 ObjectId 自动变成了下面的鬼样子

_id: {  
  _value: "662f11646e5d2ddb51ca5f1c",   
  comments: [  
    {  
      _id: "664db68ff08210b07d06956d",  
      content: "巴拉巴拉一大串"  
  ]

看着是不是很膈应?这个主表的 _id 我可是经常要用的啊,现在 要用它只能调用 data[index]._id._value,而调用副表的 _id 就更加的蛋疼了,你得这样写 data[index]._id.comments[subIndex]._id,而且这个副表内容数组外面只能被强行的包裹上副表的表名,不能自定义为一个字段名,如果副表名较长或者副表名存在前缀名(这通常是存在的)那写起来就更繁琐了,比如副表名是 uni-prefix-article-comments,再写起实际业务来就变成这样了:data[index]._id.uni-prefix-article-comments[subIndex]._id,你得时时刻刻记住这个又长又丑陋的副表名,不能使用一个简短的主表字段名代替,而且层级嵌套很深!

目前有其他变通方案解决上述的弊端吗?

也有

目前唯一能直接实现的一对多而且又可以让副表内容作为主表的一个字段的的变通方案是:首先在主表里预留一个字段 comments,其 schema 为

"comments": {  
  "bsonType": "string",  
  "foreignKey": "uni-prefix-article-comments.article_id"  
}

然后在副表里设计一个字段 article_id,它存储的值是主表的 _id

在每一次主表新插入一条数据后调用 schema.ext.js 的 afterCreate 方法,把主表的 _id 字段的值拷贝到主表的 comments 字段,这样执行联表查询时得到的结果就完全实现了副表内容作为主表的一个字段存在,查询结果如下

_id: "662f11646e5d2ddb51ca5f1c",  
comments: [  
    _id: "664db68ff08210b07d06956d",  
    content: "巴拉巴拉一大串"  
]

看上去是不是很优雅?且原来的主键 _id 还能直接调用,但实际上结果并不是那么的美好

首先是额外的增加了很多工作量,每次新插入一条数据后都要调用 afterCreate 再 update 一次,其次是数据库本来该花一次的写入费用变成了两次的写入费用,执行结果耗时更多,云计算费用成倍增长

有没有直接在主表的 schema 里配置一下就能直接实现的更好方案呢?

我查阅了官方所有的相关文档,应该说是没有,如果有请官方的工作人员来回答一下

期待官方给出的方案是什么样子的?
期待实现的完美方案是有能够像 laravel 里面的的 数据表 model 里能后写 $appends 或虚拟字段扩展方法,比如在 schema 里将字段的 bsonType 指定为 append ,增加一个描述属性指定是 hasMany 还是 hasOne,然后把关联关系写到 foreignKey 里,schema 里某个虚拟字段的 json 描述大概应该是下面这个样子

"comments": {  
  "bsonType": "append",  
  "foreignKey": "uni-prefix-article-comments.article_id == $doc._id",  
  "foreignType": "hasMany"  
}
  • alafafa (作者)

    补充一下上面的回答




    目前还有能直接实现的一种方案:每次查询操作在 afterRead 里手写查副表的逻辑,把查到的数据作为一个字段追加到主表里,这也是目前既能够实现需求而又不增加费用的方案了,且实现逻辑相比为主表预设关联字段的方案要简单,这也是我接下来能用在项目里的最优选择了,但还是期望官方能在后续版本中推出一种直接通过写 schema 配置文件就能搞定的方案

    2024-05-23 13:02

  • alafafa (作者)

    回复 alafafa: 然而我还是想多了,这种查询方式只有在单条查询的时候会在 afterRead 带来有用的 docId,在多条查询的时候无论是 docId 还是 where 都带不来任何可用参数,假如能带来有用参数的话本来单次的查询被拆分成了n次的循环查询,那带来的后果也是每次的查询都更耗时和产生更多的费用

    2024-05-23 14:05

要回复问题请先登录注册