我的需求是通过主表的数组对象的一个字段,关联另一个表的对象。
数据
主表的表结构如图所示:
{
name:{ type: String,required:true},
accountNum:{type : String ,required :true},
password:{type : String , required: true},
// 购物车
shopCart:[{
shopID:{ type: mongoose.Schema.Types.ObjectId },
number:{ type:String},
color:{type :String},
size:{type:String}
}],
}
关联表的表结构如下所示
{
_id:MongoDB自动生成的,ObjectId类型的,
shopName:{type: String , requied:true},
imageUrl:{type: String , requied:true},
price:{type: Number , requied:true},
desc:[],
size:[],
color:[],
}
需要通过主表中shopCart的shopID与关联表中的_id关联。
取一个表的数据做例子,
// 主表的数据
{
"_id" : ObjectId("5ee65a64d89f7d3d28dea864"),
"accountNum" : "gaotian",
"name" : "那棵树的看法",
"password" : "admin",
"shopCart" : [
{
"_id" : ObjectId("5ee6c7fde9d2f42f58b788ec"),
"shopID" : ObjectId("5ebfeabeb922ba458400c04d"),
"number" : "2",
"color" : "绅士灰",
"size" : "L"
},
{
"_id" : ObjectId("5ee6c7fde9d2f42f58b78845"),
"shopID" : ObjectId("5ebfeda2fa462405dcfcd7aa"),
"number" : "2",
"color" : "绅士灰",
"size" : "L"
}
]
}
//关联表的数据
//非关键数据已经省略
{
"_id" : ObjectId("5ebfeabeb922ba458400c04d"),
"desc" : [
....
],
"size" : [
....
],
"color" : [
....
],
"shopName" : "迪卡侬冰袖夏季户外跑步男女防晒手袖子防紫外线冰丝袖套护臂RUNC",
"imageUrl" : "https://img.alicdn.com/bao/uploaded/i1/352469034/O1CN01in5YZN2GbceImjsLA_!!352469034-0-lubanu-s.jpg",
"price" : 29.9,
"__v" : 0
},
{
"_id" : ObjectId("5ebfeda2fa462405dcfcd7aa"),
"desc" : [
...
],
"size" : [
....
],
"color" : [
....
],
"shopName" : "森马白色t恤女短袖宽松韩版潮小众设计感上衣女夏季纯棉落肩ins潮",
"imageUrl" : "https://img.alicdn.com/bao/uploaded/i4/397341302/O1CN01luzWS71LUMCukW1Vr-397341302.jpg",
"price" : 49.9,
"__v" : 0
}
关联代码
首先使用聚合函数,以用户表为主表,通过用户表中的数组对象shopCart中的shopID与商品表(shops)中的_id进行关联.
this.ctx.model.User.aggregate([
{
$lookup:{
from:'shops',//关联的表
localField:'shopCart.shopID',//主表关联的字段
foreignField:'_id',//关联表的字段
as:"shop"//生成的数据放在shop中
}
}
])
通常主表中有很多数据对象,我们要找到我们想要的那个数据对象。比如我们要accountNum是 gaotian的用户。
this.ctx.model.User.aggregate([
{
$lookup:{
from:'shops',//关联的表
localField:'shopCart.shopID',//主表关联的字段
foreignField:'_id',//关联表的字段
as:"shop"//生成的数据放在shop中
}
},{
$match:{
"accountNum":'gaotian' //找到我们想要关联的主表
}
}
])
这时候的返回的结果的结构也不是我们想要的,我们要是用使用unwind对数据进行结构,在使用project 进行重组。
this.ctx.model.User.aggregate([
{
$lookup:{
from:'shops',//关联的表
localField:'shopCart.shopID',//主表关联的字段
foreignField:'_id',//关联表的字段
as:"shop"//生成的数据放在shop中
}
},{
$match:{
"accountNum":'gaotian' //找到我们想要关联的主表
}
},{
$unwind:{
path:"$shop",
preserveNullAndEmptyArrays:true
}
},{
$unwind:{
path:"$shopCart",
preserveNullAndEmptyArrays:true
}
}, {
$project: {
"carid":'$shopCart._id',
'shopid':'$shop._id',
'shopName':"$shop.shopName",
'imageUrl': "$shop.imageUrl",
'price': "$shop.price",
"number":'$shopCart.number',
"size":'$shopCart.size',
"color":"$shopCart.color",
"isnumber":"$shop.isnumber",
'flag':{$eq :["$shopCart.shopID","$shop._id"]}
}
}
])
这个地方的unwind的作用说白了就是打散shop和shopCart这两组数据,打散之后你会发现shopCart和shop中的数据进行了两两配对,一共出现了四种结果。
project就是挑出你要显示的键名和键值,键名是自己起的。
但是他这是两两配对了,出来了四种结果,并没有把我们想要的。然后我们就可以用通过比较运算符来进行筛选。eq是等于运算符,如果shopCart.shopID和shop._id相等就会返回true。
image.png
this.ctx.model.User.aggregate([
{
$lookup:{
from:'shops',//关联的表
localField:'shopCart.shopID',//主表关联的字段
foreignField:'_id',//关联表的字段
as:"shop"//生成的数据放在shop中
}
},{
$match:{
"accountNum":'gaotian' //找到我们想要关联的主表
}
},{
$unwind:{
path:"$shop",
preserveNullAndEmptyArrays:true
}
},{
$unwind:{
path:"$shopCart",
preserveNullAndEmptyArrays:true
}
}, {
$project: {
"carid":'$shopCart._id',
'shopid':'$shop._id',
'shopName':"$shop.shopName",
'imageUrl': "$shop.imageUrl",
'price': "$shop.price",
"number":'$shopCart.number',
"size":'$shopCart.size',
"color":"$shopCart.color",
"isnumber":"$shop.isnumber",
'flag':{$eq :["$shopCart.shopID","$shop._id"]}
}
},{
$match :{
'flag':true
}
},
{
$project: {
'flag': 0
}
}
])
然后我们可以在通过match筛选flag为true的数据,那这组就是我们想要的数据了。最后再加上一个文档重组。