在 GraphQL 解析器中链接集合
Posted
技术标签:
【中文标题】在 GraphQL 解析器中链接集合【英文标题】:Linking collections in GraphQL resolver 【发布时间】:2021-02-02 01:07:32 【问题描述】:我正在尝试在 GraphQL 查询中加入两个集合。
我的数据如下: 游轮:
[
"cruiseID" : "00001",
"title" : "title 1",
"description" : "desc 1",
"startDate" : 20150820,
"endDate" : 20150827,
"numDays" : 8,
"startPort" : "Juneau, Alaska",
"roomTypes" : [
"roomID" : "IPD",
"roomID" : "SDS"
]
,
"cruiseID" : "00002",
"title" : "title 1",
"description" : "desc 2",
"startDate" : 20150710,
"endDate" : 20150724,
"numDays" : 14,
"startPort" : "San Diego",
"roomTypes" : [
"roomID" : "IPD",
"roomID" : "SJS",
"roomID" : "SDS"
]
]
房间:
[
"roomID": "IPD",
"roomDetails":
"roomType": "IPD aaaaa",
"title": "aaaa",
"description": "ddddd",
"maxOccupants": 2
,
"capacity": [
"cruiseID": "00001", "total": 21, "available": 20,
"cruiseID": "00002", "total": 31, "available": 30
]
,
"roomID": "SJS",
"roomDetails":
"roomType": "SJS aaaa",
"title": "aaaaa",
"description": "aaaaa",
"maxOccupants": 4
,
"capacity": [
"cruiseID": "00001", "available": 27,
"cruiseID": "00002", "available": 27
]
,
"roomID": "SDS",
"roomDetails":
"roomType": "SDS aaa",
"title": "sssss",
"description": "sssssss",
"maxOccupants": 4
,
"capacity": [
"cruiseID": "00001", "available": 20,
"cruiseID": "00002", "available": 20
]
]
我的 GraphQL 架构:
type Query
Cruises: [Cruise]
type RoomDetails
roomType: String
title: String
description: String
maxOccupants: Int
type Capacity
cruiseID: String
total: Int
available: Int
type Room
roomID: String
roomDetails: RoomDetails
capacity: [Capacity]
type Cruise
_id: ID
cruiseID: String
title: String
description: String
startDate: Int
endDate: Int
numDays: Int
startPort: String
roomTypes: [Room]
我的 GraphQL 解析器,我尝试通过从房间集合中读取房间类型来打印房间类型的详细信息:
const Query =
Cruises: async () =>
data = await db.collection('cruises').find().toArray().then(res => return res );
return data
const Cruise =
roomTypes: async (root) =>
data = await db.collection('rooms').find('roomID': 'SDS').toArray().then(res => return res );
// prints OK
logger.debug(`root.roomTypes.roomID': $JSON.stringify(root.roomTypes[1].roomID)`);
// undefined
logger.debug(`root.roomTypes.roomID': $JSON.stringify(root.roomTypes.roomID)`);
// prints OK
logger.debug(`root.startPort': $root.startPort`);
return data
module.exports =
Query,
Cruise
我在 Cruises 和 Rooms 之间找不到合适的连接。 硬编码 'roomID': 'SDS' 工作正常,即显示正确的输出。 但是,我找不到正确将 Cruises 中的 roomID 传递给 find 过滤器的方法。有什么提示吗?
更新: 当我实现解析器生命时:
const Cruise =
roomTypes: async (root) =>
data = await db.collection('rooms').find('capacity.cruiseID': root.cruiseID).toArray().then(res => return res )
//data = await db.collection('rooms').find().toArray().then(res => return res )
return data
我取回了数据(roomTypes 完全解析),但它实际上并没有进行任何过滤/加入。 这是我得到的(用一些垃圾数据编辑,所以它更短):
"data":
"Cruises": [
"cruiseID": "00001",
"title": "and",
"startDate": 20150820,
"endDate": 20150827,
"numDays": 8,
"startPort": "Juneau, Alaska",
"roomTypes": [
"roomID": "IPD",
"roomDetails":
"roomType": "asd",
"title": "and",
"description": "asdr",
"maxOccupants": 2
,
"capacity": [
"cruiseID": "00001",
"total": 21,
"available": 20
,
"cruiseID": "00002",
"total": 31,
"available": 30
]
,
"roomID": "OPD",
"roomDetails":
"roomType": "ad",
"title": "and",
"description": "asdr",
"maxOccupants": 2
,
"capacity": [
"cruiseID": "00001",
"total": null,
"available": 30
,
"cruiseID": "00002",
"total": null,
"available": 30
]
,
"roomID": "SDD",
"roomDetails":
"roomType": "asd",
"title": "and",
"description": "and",
"maxOccupants": 2
,
"capacity": [
"cruiseID": "00001",
"total": null,
"available": 25
,
"cruiseID": "00002",
"total": null,
"available": 25
]
,
"roomID": "SD2",
"roomDetails":
"roomType": "asd",
"title": "and",
"description": "Fast",
"maxOccupants": 4
,
"capacity": [
"cruiseID": "00001",
"total": null,
"available": 22
,
"cruiseID": "00002",
"total": null,
"available": 22
]
,
"roomID": "SJS",
"roomDetails":
"roomType": "asd",
"title": "and",
"description": "Tasdr",
"maxOccupants": 4
,
"capacity": [
"cruiseID": "00001",
"total": null,
"available": 27
,
"cruiseID": "00002",
"total": null,
"available": 27
]
,
"roomID": "SDS",
"roomDetails":
"roomType": "asd",
"title": "and",
"description": "Tase",
"maxOccupants": 4
,
"capacity": [
"cruiseID": "00001",
"total": null,
"available": 20
,
"cruiseID": "00002",
"total": null,
"available": 20
]
]
,
而不是根据 Cruises 集合中的条目仅列出 CruiseID 00001 的 2 种房间类型(IPD、SDS)。
【问题讨论】:
Cruise.roomTypes
(subfield) resolver then 'cruises' collection (not 'rooms') find by root.id (cruise) "cruiseID" : root.id ... 已经是一个数组 ...然后在循环中按容量条目匹配 Cruiseid 的类型查找房间
感谢您的评论。但是,我不明白你的评论。你能解释一下吗?
Resolver chains
在这里试试:apollographql.com/docs/apollo-server/data/resolvers/…。遵循代码示例(否则有点难以理解这个想法)。 Library
& Books
(在你的情况下Cruise
& Rooms
)
Cruise = roomTypes
.... roomTypes
已在 Query.Cruises 中解决(部分 - 仅来自游轮条目的 roomId 道具 - 覆盖,也许你想要一些“房间”道具?) ?控制台日志(数据)? ...您需要解决“缺少”房间类型属性(roomDetails,容量)... Room.roomDetails 解析器将使用 roomID 获取房间作为父级(但阿波罗缓存需要每个类型的“id”/“_id”唯一字段 -房间详情)
请在问题中查看我的更新。我正在解决房间类型。我只是无法在其中获取正确的数据。
【参考方案1】:
这就是我最终做到的方式。这不是最干净的代码/解决方案,但它可以完成工作。
const Cruise =
roomTypes: async (root) =>
let rooms = root.roomTypes;
allRooms = await db.collection('rooms').find().toArray().then(res => return res );
rooms.forEach(room =>
let currentRoomID = room.roomID;
currentRoom = allRooms.filter(function(r)
return r.roomID === currentRoomID;
);
currentRoomCapacity = currentRoom[0].capacity.filter(function(c)
return c.cruiseID === root.cruiseID;
);
room.roomDetails = currentRoom[0].roomDetails
room.capacity = currentRoomCapacity
);
return rooms;
【讨论】:
以上是关于在 GraphQL 解析器中链接集合的主要内容,如果未能解决你的问题,请参考以下文章
express-graphql 解析器参数在解析器中为空,但 info variableValues 填充了名称和值
从 Rest(Express) 迁移到 GraphQL:模型(mongoose) 在 graphQL 解析器中不起作用
如何在 GraphQL 解析器中添加用于缓存的 redis 客户端
Meteor Apollo GraphQL 接口:返回一个对象数组并在另一个解析器中调用解析器