在 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 接口:返回一个对象数组并在另一个解析器中调用解析器

Apollo GraphQL 服务器:在解析器中,从更高级别获取变量

使用 graphql 和 apollo-server 在解析器中获取会话