SpaceX-API Launch 查询接口实战指南:使用 POST /v4/launches/query 实现 MongoDB 聚合查询与分页
2026/9/23 15:29:27 网站建设 项目流程
  • 后端
  • API设计

【免费下载链接】SpaceX-API

:rocket: Open Source REST API for SpaceX launch, rocket, core, capsule, starlink, launchpad, and landing pad data.

项目地址:https://gitcode.com/gh_mirrors/spa/SpaceX-API
点击查看免费下载

本文基于 SpaceX-API 开源仓库中的 launches/v4/query.md 文档,深入讲解如何通过POST /v4/launches/query端点对发射(Launch)数据进行 MongoDB 查询、条件过滤、排序分页与关联数据填充(populate)。读完后你将能够编写从简单到复杂的查询请求体、理解分页返回结构与关联字段的填充机制,并结合源码掌握其底层实现原理与缓存行为。

接口概览:方法、URL 与鉴权

/v4/launches/query是 SpaceX-API 中面向发射数据的高阶查询端点,与返回全部数据的GET /v4/launches不同,它允许开发者通过请求体(Body)自定义过滤、排序、分页与字段选择,避免全量拉取后在客户端再做筛选。

项目
MethodPOST
URLhttps://api.spacexdata.com/v4/launches/query
Auth requiredFalse
BodyJSON,包含queryoptions两个字段

请求体默认结构如下:

{ "query": {}, "options": {} }
  • query:任何合法的 MongoDBfind()查询文档,用于过滤发射记录;
  • options:分页与输出控制选项,由mongoose-paginate-v2插件解析。

在仓库源码中,该路由定义于 routes/launches/v4/index.js,其核心逻辑为:

router.post('/query', cache(20), async (ctx) => { const { query = {}, options = {} } = await transformQuery(ctx.request.body); try { const result = await Launch.paginate(query, options); ctx.status = 200; ctx.body = await transformResponse(result); } catch (error) { ctx.throw(400, error.message); } });

可以看到:请求体经transformQuery预处理后,直接交给Launch.paginate(query, options)执行,因此queryoptions的语义完全对应mongoose-paginate-v2的参数约定。查询无需任何鉴权;仓库中auth中间件仅用于创建、更新、删除等破坏性路由(见 routes/launches/v4/index.js)。

关于完整的查询与分页语法,请参阅仓库根目录下的 docs/queries.md 通用指南,下文将结合发射数据的特有字段展开具体用法。

深入 query:基于 MongoDB find() 的过滤语法

query字段接受任意合法的 MongoDB 查询操作符,因此你可以在发射数据上使用全部标准查询操作符,例如:

  • 比较操作符:$eq$ne$gt$gte$lt$lte$in$nin
  • 逻辑操作符:$and$or$not$nor
  • 元素与数组操作符:$exists$size$all$elemMatch
  • 文本搜索:$text(配合$search$language等子操作符)。

示例一:按日期区间过滤

发射文档中的date_utc以 ISO 8601 字符串存储,比较操作符可直接作用于日期字符串。以下查询返回 2017-06-22 至 2017-06-25 之间的所有发射:

{ "query": { "date_utc": { "$gte": "2017-06-22T00:00:00.000Z", "$lte": "2017-06-25T00:00:00.000Z" } } }

注意:日期必须使用 ISO 8601 格式,操作符才能正确进行字典序比较。

示例二:全文搜索

$text会搜索集合中所有文本索引。仓库的 Launch 模型在 models/launches.js 中对namedetails建立了文本索引:

const index = { name: 'text', details: 'text', }; launchSchema.index(index);

因此以下查询会同时匹配名称与详情描述中的关键字crs

{ "query": { "$text": { "$search": "crs" } } }

示例三:查找下一次即将发射

组合upcoming: true过滤与按flight_number升序排序,取limit: 1即可得到下一次发射:

{ "query": { "upcoming": true }, "options": { "limit": 1, "sort": { "flight_number": "asc" } } }

示例四:复杂组合查询

以下查询综合运用了日期区间、$or逻辑、$in枚举过滤与排序限制:

{ "query": { "date_utc": { "$gte": "2017-06-22T00:00:00.000Z", "$lte": "2017-06-25T00:00:00.000Z" }, "$or": [ { "flight_number": { "$gt": 30 } }, { "tbd": true } ], "date_precision": { "$in": [ "month", "day" ] } }, "options": { "sort": { "flight_number": "asc" }, "limit": 50 } }

该查询的含义:在指定日期区间内,飞行编号大于 30日期待定(tbd: true),并且date_precisionmonthday的发射记录,按flight_number升序排列,最多返回 50 条。

可查询字段速查(来自 Launch Schema)

query中可用的字段即 docs/launches/v4/schema.md 中定义的 Launch Schema,常用过滤字段包括:

字段类型说明
flight_numberNumber发射编号
nameString(唯一)发射任务名称
date_utcStringISO 8601 UTC 日期
date_unixNumberUNIX 时间戳(秒)
date_localString本地时间(含时区偏移)
date_precisionString日期精度,枚举值halfquarteryearmonthdayhour
static_fire_date_utcString静态点火日期
static_fire_date_unixNumber静态点火 UNIX 时间戳
tbdBoolean日期是否待定
netBoolean日期是否为"不早于"
windowNumber发射窗口(秒)
rocketUUID关联火箭 ID
successBoolean是否成功
upcomingBoolean是否即将发射
detailsString任务详情
fairingsObject整流罩信息
crewUUID[]乘组成员 ID
shipsUUID[]关联船只 ID
capsulesUUID[]关联龙飞船 ID
payloadsUUID[]关联有效载荷 ID
launchpadUUID发射场 ID
coresObject[]一级芯级详情
linksObject媒体链接集合

对应的完整字段定义见源码 models/launches.js。

掌握 options:排序、分页与字段选择

optionsmongoose-paginate-v2解析,支持以下常用配置项:

选项类型说明
selectObject / String指定返回哪些字段,默认返回全部字段
sortObject / String排序规则,如{ "flight_number": "asc" }
offsetNumber跳过条数(与page二选一)
pageNumber页码(从 1 开始)
limitNumber每页条数
paginationBoolean设为false时返回全部文档,不附加 limit 条件(默认true
populateArray / Object / String需要填充的关联路径

其中populate是本 API 最强大的能力之一,见下文专节。

分页返回结构解析

成功响应为200 OK,返回mongoose-paginate-v2标准分页结构。以docs/launches/v4/query.md中的响应为例:

{ "docs": [ { "fairings": { "reused": false, "recovery_attempt": true, "recovered": false, "ships": ["5ea6ed2e080df4000697c908"] }, "links": { "patch": { "small": "https://images2.imgbox.com/02/51/7NLaBm8c_o.png", "large": "https://images2.imgbox.com/69/f5/04lBXd2F_o.png" }, "reddit": { "campaign": "https://www.reddit.com/r/spacex/comments/73ttkd/koreasat_5a_launch_campaign_thread/", "launch": "https://www.reddit.com/r/spacex/comments/79iuvb/rspacex_koreasat_5a_official_launch_discussion/", "media": "https://www.reddit.com/r/spacex/comments/79lmdu/rspacex_koreasat5a_media_thread_videos_images/", "recovery": null }, "flickr": { "small": [], "original": [ "https://farm5.staticflickr.com/4477/38056454431_a5f40f9fd7_o.jpg", "https://farm5.staticflickr.com/4455/26280153979_b8016a829f_o.jpg", "https://farm5.staticflickr.com/4459/38056455051_79ef2b949a_o.jpg", "https://farm5.staticflickr.com/4466/26280153539_ecbc2b3fa9_o.jpg", "https://farm5.staticflickr.com/4482/26280154209_bf08d76361_o.jpg", "https://farm5.staticflickr.com/4493/38056455211_a4565a9cee_o.jpg" ] }, "presskit": "http://www.spacex.com/sites/spacex/files/koreasat5apresskit.pdf", "webcast": "https://www.youtube.com/watch?v=RUjH14vhLxA", "youtube_id": "RUjH14vhLxA", "article": "https://spaceflightnow.com/2017/10/30/spacex-launches-and-lands-third-rocket-in-three-weeks/", "wikipedia": "https://en.wikipedia.org/wiki/Koreasat_5A" }, "static_fire_date_utc": "2017-10-26T16:00:00.000Z", "static_fire_date_unix": 1509033600, "tdb": false, "net": false, "window": 8640, "rocket": "5e9d0d95eda69973a809d1ec", "success": true, "failures": [], "details": "KoreaSat 5A is a Ku-band satellite ...", "crew": [], "ships": [ "5ea6ed2f080df4000697c90d", "5ea6ed2e080df4000697c908", "5ea6ed30080df4000697c913" ], "capsules": [], "payloads": ["5eb0e4c5b6c3bb0006eeb217"], "launchpad": "5e9e4502f509094188566f88", "auto_update": true, "flight_number": 50, "name": "KoreaSat 5A", "date_utc": "2017-10-30T19:34:00.000Z", "date_unix": 1509392040, "date_local": "2017-10-30T15:34:00-04:00", "date_precision": "hour", "upcoming": false, "cores": [ { "core": "5e9e28a4f359185cc03b2651", "flight": 1, "gridfins": true, "legs": true, "reused": false, "landing_attempt": true, "landing_success": true, "landing_type": "ASDS", "landpad": "5e9e3032383ecb6bb234e7ca" } ], "id": "5eb87d0dffd86e000604b35b" } ], "totalDocs": 109, "limit": 10, "totalPages": 11, "page": 5, "pagingCounter": 41, "hasPrevPage": true, "hasNextPage": true, "prevPage": 4, "nextPage": 6 }

分页元数据字段含义如下:

字段说明
docs当前页数据数组
totalDocs符合条件的总文档数
offset当前页跳过条数
limit每页条数
totalPages总页数
page当前页码
pagingCounter当前页首条记录的全局序号(本例(page-1)*limit+1 = 41
hasPrevPage/hasNextPage是否有上一页 / 下一页
prevPage/nextPage上一页 / 下一页页码(不存在时为null

默认分页返回结构(未指定任何 options)为:

{ "docs": [], "totalDocs": 0, "offset": 0, "limit": 10, "totalPages": 1, "page": 1, "pagingCounter": 1, "hasPrevPage": false, "hasNextPage": false, "prevPage": null, "nextPage": null }

注意响应中的日期语义:date_utc为 UTC 时间,date_local为带时区偏移的本地时间,date_precision表示日期精度。例如当date_precisionmonth时,日期仅精确到月份级别(相关 FAQ 见 docs/README.md)。

使用 populate 关联填充:把 UUID 变成完整文档

发射文档中的rocketpayloadscores.corelaunchpadshipscapsules等字段默认以 UUID 形式存储,指向其他集合中的文档。例如:

{ "payloads": [ "5eb0e4c6b6c3bb0006eeb21e" ] }

populate选项可以"替换"这些 UUID 为对应的完整文档,实现一次请求获取完整的关联数据链。

基础填充

https://api.spacexdata.com/v4/launches/query发送以下请求体,即可将每个发射的payloads替换为完整的有效载荷对象:

{ "query": {}, "options": { "populate": [ "payloads" ] } }

返回结果中payloads变为对象数组:

{ "payloads": [ { "dragon": { "capsule": null, "mass_returned_kg": null, "mass_returned_lbs": null, "flight_time_sec": null, "manifest": null, "water_landing": null, "land_landing": null }, "name": "Tintin A & B", "type": "Satellite", "reused": false, "launch": "5eb87d14ffd86e000604b361", "customers": ["SpaceX"], "norad_ids": [43216, 43217], "nationalities": ["United States"], "manufacturers": ["SpaceX"], "mass_kg": 800, "mass_lbs": 1763.7, "orbit": "SSO", "reference_system": "geocentric", "regime": "low-earth", "longitude": null, "semi_major_axis_km": 6737.42, "eccentricity": 0.0012995, "periapsis_km": 350.53, "apoapsis_km": 368.04, "inclination_deg": 97.4444, "period_min": 91.727, "lifespan_years": 1, "epoch": "2020-06-13T13:46:31.000Z", "mean_motion": 15.69864906, "raan": 176.6734, "arg_of_pericenter": 174.2326, "mean_anomaly": 185.9087, "id": "5eb0e4c6b6c3bb0006eeb21e" } ] }

填充时选择字段

populate支持对象形式,通过path指定关联路径、select限制返回字段。例如只关心有效载荷名称:

{ "options": { "populate": [ { "path": "payloads", "select": { "name": 1 } } ] } }

返回结果:

{ "payloads": [ { "name": "Tintin A & B", "id": "5eb0e4c6b6c3bb0006eeb21e" } ] }

嵌套填充

populate可以递归嵌套,例如先填充payloads,再填充每个有效载荷对象内部的launch字段:

{ "options": { "populate": [ { "path": "payloads", "populate": [ { "path": "launch" } ] } ] } }

crew 字段的特殊处理

v4 的 Launch 模型中,crew是对象数组,每个元素形如{ "crew": UUID, "role": String }(见 models/launches.js),而 v5 中则直接是 UUID 数组。为了保证 v4 与 v5 返回结构一致,仓库做了两层处理:

  1. 请求侧的transformQuery在 populate 时自动将crew路径改写为crew.crew(见 routes/launches/v4/_transform-query.js);
  2. 响应侧的transformResponse会将填充后的crew数组重新构建为纯 UUID 数组(见 routes/launches/v4/_transform-response.js)。

这意味着即使你在populate中填写"crew",也会被自动映射到正确路径;而返回时crew字段始终以数组形式呈现,无需关心内部结构差异。

错误响应与排查

400 Bad Request:当queryoptions语法非法(例如 MongoDB 操作符拼写错误、字段名不存在、日期格式不合法)时,接口返回400,响应体中直接携带 Mongoose/MongoDB 的报错信息与修正建议:

Code:400 Bad Request

Content: Mongoose error is shown, with suggestions to fix the query.

从源码看,路由内所有查询异常都会被捕获并以ctx.throw(400, error.message)抛出(routes/launches/v4/index.js),因此响应体的错误信息即底层数据库的原始错误文本,可直接据此修正查询。

性能与缓存行为

/v4/launches/query路由应用了cache(20)中间件(routes/launches/v4/index.js),即发射数据的查询结果会被缓存 20 秒。从 middleware/cache.js 的源码可以看出:

  • 缓存基于 Redis,键由HTTP 方法 + URL + 请求体 JSON经 BLAKE3 哈希生成,因此相同请求体的重复请求会命中缓存;
  • 响应头spacex-api-cache: HIT表示命中缓存,MISS表示未命中;
  • NODE_ENVproduction或 Redis 不可用时,中间件自动降级为直接放行,不影响接口可用性;
  • 生产环境下,POSTGET请求都在可缓存方法白名单内。

相关缓存说明见 docs/README.md。

与其他端点配合使用

/v4/launches/query与同模块其他端点互补:

  • GET /v4/launches:返回全部发射,按flight_number升序;
  • GET /v4/launches/:id:按 ID 返回单条发射;
  • GET /v4/launches/past:返回历史发射(upcoming: false);
  • GET /v4/launches/upcoming:返回即将发射(upcoming: true);
  • GET /v4/launches/latest:返回最近一次历史发射;
  • GET /v4/launches/next:返回下一次发射;

以上路由的完整定义与实现见 routes/launches/v4/index.js。当内置便捷端点无法满足筛选需求时,即可改用POST /v4/launches/query组合任意条件。对应文档还包括 docs/launches/v4/all.md、docs/launches/v4/one.md、docs/launches/v4/past.md、docs/launches/v4/upcoming.md、docs/launches/v4/latest.md 与 docs/launches/v4/next.md。

小结

本文围绕POST /v4/launches/query完整讲解了请求结构、MongoDB 过滤语法、分页与排序选项、分页响应结构、关联填充技巧及错误处理。总结要点如下:

  1. query接受任意 MongoDBfind()查询,日期需使用 ISO 8601 格式,文本搜索依赖name/details的文本索引;
  2. options支持selectsortpageoffsetlimitpaginationpopulate
  3. 返回结构为mongoose-paginate-v2标准分页结构,字段包括docstotalDocstotalPages等;
  4. 关联字段默认返回 UUID,通过populate可替换为完整文档,支持字段选择与嵌套填充;
  5. 查询结果缓存 20 秒,相同请求体可命中 Redis 缓存;
  6. 语法错误返回400,错误体为数据库原始提示,可直接据此修正。

如需进一步了解通用查询语法,可继续阅读 docs/queries.md;若想深入 Launch 数据模型,可查看 docs/launches/v4/schema.md 与源码 models/launches.js。

  • 后端
  • API设计

【免费下载链接】SpaceX-API

:rocket: Open Source REST API for SpaceX launch, rocket, core, capsule, starlink, launchpad, and landing pad data.

项目地址:https://gitcode.com/gh_mirrors/spa/SpaceX-API
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询