求助:使用Retrofit向Mlab发送含$addToSet的PUT请求遇阻
解决Retrofit发送mLab $addToSet PUT请求的问题
我之前也遇到过类似的情况,Postman能跑通但Retrofit里就出问题,大多是请求结构或者序列化的细节没处理好。结合你的场景,咱们一步步来解决:
1. 先确认依赖配置
确保你已经添加了Retrofit和Gson转换器(用来处理JSON序列化),在build.gradle里加上:
implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
2. 定义请求体数据类
MongoDB的$addToSet是带$符号的操作符,Gson默认不会自动识别这种字段,所以必须用@SerializedName显式指定:
// Kotlin版本 data class UpdateWalkRequest( @SerializedName("$addToSet") // 关键:转义$符号 val addToSet: WalkUpdateData ) data class WalkUpdateData( val completedWalks: String // 要添加的单条步道名称;如果要加多条,改成List<String> )
如果是Java的话,对应的POJO类:
// Java版本 public class UpdateWalkRequest { @SerializedName("$addToSet") private WalkUpdateData addToSet; public UpdateWalkRequest(WalkUpdateData addToSet) { this.addToSet = addToSet; } // getter & setter } public class WalkUpdateData { private String completedWalks; public WalkUpdateData(String completedWalks) { this.completedWalks = completedWalks; } // getter & setter }
3. 定义Retrofit接口
mLab的更新接口需要指定数据库名、集合名,还要带API密钥、查询条件(用来定位要更新的文档):
// Kotlin版本 interface MlabApiService { @PUT("databases/{dbName}/collections/{collectionName}") suspend fun updateUserCompletedWalks( @Path("dbName") dbName: String, @Path("collectionName") collectionName: String, @Query("apiKey") apiKey: String, @Query("q") query: String, // 查询条件,比如{"email":"test@gmail.com"}的字符串形式 @Query("upsert") upsert: Boolean = false, // 可选:无匹配文档时是否插入 @Body request: UpdateWalkRequest ): Response<Void> }
Java版本的接口:
// Java版本 public interface MlabApiService { @PUT("databases/{dbName}/collections/{collectionName}") Call<Void> updateUserCompletedWalks( @Path("dbName") String dbName, @Path("collectionName") String collectionName, @Query("apiKey") String apiKey, @Query("q") String query, @Query("upsert") boolean upsert, @Body UpdateWalkRequest request ); }
4. 初始化Retrofit并发起请求
Kotlin(用协程)
// 创建Retrofit实例 val retrofit = Retrofit.Builder() .baseUrl("https://api.mlab.com/api/1/") // mLab的基础API地址 .addConverterFactory(GsonConverterFactory.create()) .build() val mlabApi = retrofit.create(MlabApiService::class.java) // 发起请求 CoroutineScope(Dispatchers.IO).launch { // 注意:查询条件要转成JSON字符串,引号需要转义 val query = "{\"email\":\"test@gmail.com\"}" val updateRequest = UpdateWalkRequest(WalkUpdateData("South Leinster Way")) val response = mlabApi.updateUserCompletedWalks( dbName = "你的数据库名", collectionName = "你的集合名", apiKey = "你的mLab API密钥", query = query, request = updateRequest ) if (response.isSuccessful) { // 更新成功,回到主线程处理UI withContext(Dispatchers.Main) { // 比如弹出提示 } } else { // 打印错误信息排查问题 val errorMsg = response.errorBody()?.string() Log.e("MlabError", "更新失败: $errorMsg") } }
Java(用回调)
// 创建Retrofit实例 Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.mlab.com/api/1/") .addConverterFactory(GsonConverterFactory.create()) .build(); MlabApiService mlabApi = retrofit.create(MlabApiService.class); // 发起请求 String query = "{\"email\":\"test@gmail.com\"}"; UpdateWalkRequest request = new UpdateWalkRequest(new WalkUpdateData("South Leinster Way")); Call<Void> call = mlabApi.updateUserCompletedWalks( "你的数据库名", "你的集合名", "你的mLab API密钥", query, false, request ); call.enqueue(new Callback<Void>() { @Override public void onResponse(Call<Void> call, Response<Void> response) { if (response.isSuccessful()) { // 更新成功 } else { try { String errorMsg = response.errorBody().string(); Log.e("MlabError", "更新失败: " + errorMsg); } catch (IOException e) { e.printStackTrace(); } } } @Override public void onFailure(Call<Void> call, Throwable t) { t.printStackTrace(); } });
常见问题排查
- $addToSet字段未被识别:一定要用
@SerializedName("$addToSet"),Gson默认不会处理带$的字段 - 查询参数q格式错误:必须是合法的JSON字符串,比如
{"email":"test@gmail.com"}要转义成字符串形式传递 - 请求方法错误:mLab更新文档必须用PUT,并且要带
q参数定位文档 - 权限问题:确保你的API密钥有该数据库的写入权限
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

