您在使用 Spring Data MongoDB 時遇到了 InvalidMongoDbApiUsageException
異常,錯誤信息如下:
“由于 com.mongodb.BasicDocument 的限制,您無法添加第二個 ‘null’ 條件。查詢已經包含 ‘{ “KaTeX parse error: Expected '}', got 'EOF' at end of input: …castTime" : { "lte” : { “KaTeX parse error: Expected 'EOF', got '}' at position 31: …4-21T16:00:00Z"}?}, "and” : [{ “broadcastTime” : { “KaTeX parse error: Expected '}', got 'EOF' at end of input: gte" : { "date” : “2025-04-20T16:00:00Z”}}}]}, { “planBroadcastTime” : { “KaTeX parse error: Expected '}', got 'EOF' at end of input: lte" : { "date” : “2025-04-21T16:00:00Z”}}, “KaTeX parse error: Expected '}', got 'EOF' at end of input: …castTime" : { "gte” : { “$date” : “2025-04-20T16:00:00Z”}}}]}]}’”
這個錯誤是由使用 Criteria
API 構建 MongoDB 查詢時的錯誤用法引起的。以下是問題的分析和解決方案。
問題分析
假設您的代碼類似于以下形式,用于根據時間范圍和回退條件查詢數據:
Query query = new Query();
if (liveRoomReq.getStartTime() != null && liveRoomReq.getEndTime() != null) {Criteria timeCriteria = new Criteria().orOperator(Criteria.where("broadcastTime").lte(liveRoomReq.getEndTime()).andOperator(Criteria.where("broadcastTime").gte(liveRoomReq.getStartTime())),Criteria.where("planBroadcastTime").lte(liveRoomReq.getEndTime()).andOperator(Criteria.where("planBroadcastTime").gte(liveRoomReq.getStartTime())));query.addCriteria(timeCriteria);
}
上述代碼嘗試構建一個查詢,要求 broadcastTime
或 planBroadcastTime
在指定的 startTime
和 endTime
范圍內。但錯誤的使用方式導致了無效的 MongoDB 查詢結構。
生成的錯誤查詢
根據錯誤信息,生成的 MongoDB 查詢如下:
{"$or": [{"broadcastTime": { "$lte": { "$date": "2025-04-21T16:00:00Z" } },"$and": [ { "broadcastTime": { "$gte": { "$date": "2025-04-20T16:00:00Z" } } } ]},{"planBroadcastTime": { "$lte": { "$date": "2025-04-21T16:00:00Z" } },"$and": [ { "planBroadcastTime": { "$gte": { "$date": "2025-04-20T16:00:00Z" } } } ]}]
}
這種結構是無效的,因為 MongoDB 不允許在同一字段的條件中混合使用字段運算符(如 $lte
)和邏輯運算符(如 $and
)。正確的范圍查詢應該將 $lte
和 $gte
組合在同一個字段的對象中。
錯誤原因
問題出在 .andOperator
的誤用上:
- 在 Spring Data MongoDB 中,
.andOperator
用于將多個不同字段的條件以 AND 邏輯組合。 - 對于同一字段的范圍查詢(如
broadcastTime
需要同時滿足<= endTime
和>= startTime
),應該在單個Criteria
上直接鏈式調用.lte()
和.gte()
。
錯誤的用法生成了不符合 MongoDB 語法的查詢結構,導致 Spring Data MongoDB 在處理后續條件時拋出異常。
解決方案
修復方法是調整 Criteria
的構建方式,在同一字段的條件上直接使用鏈式調用,而不是使用 .andOperator
。以下是更正后的代碼:
Query query = new Query();
if (liveRoomReq.getStartTime() != null && liveRoomReq.getEndTime() != null) {Criteria broadcastTimeCriteria = Criteria.where("broadcastTime").lte(liveRoomReq.getEndTime()).gte(liveRoomReq.getStartTime());Criteria planBroadcastTimeCriteria = Criteria.where("planBroadcastTime").lte(liveRoomReq.getEndTime()).gte(liveRoomReq.getStartTime());Criteria timeCriteria = new Criteria().orOperator(broadcastTimeCriteria, planBroadcastTimeCriteria);query.addCriteria(timeCriteria);
} else if (liveRoomReq.getStartTime() != null) {Criteria broadcastTimeCriteria = Criteria.where("broadcastTime").gte(liveRoomReq.getStartTime());Criteria planBroadcastTimeCriteria = Criteria.where("planBroadcastTime").gte(liveRoomReq.getStartTime());Criteria timeCriteria = new Criteria().orOperator(broadcastTimeCriteria, planBroadcastTimeCriteria);query.addCriteria(timeCriteria);
}
// 添加回退條件(示例)
if (StringUtil.isNotEmptyString(liveRoomReq.getFallback())) {if ("0".equals(liveRoomReq.getFallback())) {Criteria fallbackCriteria = new Criteria().orOperator(Criteria.where("fallback").in(liveRoomReq.getFallback()),Criteria.where("fallback").exists(false));query.addCriteria(fallbackCriteria);} else {query.addCriteria(Criteria.where("fallback").is(liveRoomReq.getFallback()));}
}
修復后的查詢
對于 startTime
和 endTime
都提供的情況,生成的 MongoDB 查詢如下:
{"$or": [{ "broadcastTime": { "$lte": "2025-04-21T16:00:00Z", "$gte": "2025-04-20T16:00:00Z" } },{ "planBroadcastTime": { "$lte": "2025-04-21T16:00:00Z", "$gte": "2025-04-20T16:00:00Z" } }]
}
如果還添加了 fallback
條件(例如 fallback = "0"
),最終查詢可能是:
{"$and": [{"$or": [{ "broadcastTime": { "$lte": "2025-04-21T16:00:00Z", "$gte": "2025-04-20T16:00:00Z" } },{ "planBroadcastTime": { "$lte": "2025-04-21T16:00:00Z", "$gte": "2025-04-20T16:00:00Z" } }]},{"$or": [{ "fallback": { "$in": ["0"] } },{ "fallback": { "$exists": false } }]}]
}
這是一個有效的 MongoDB 查詢結構。
為什么這個方案有效
-
正確的范圍查詢
在同一字段的Criteria
上鏈式調用.lte()
和.gte()
,確保條件被正確分組到一個對象中,符合 MongoDB 的語法要求。 -
邏輯運算符的正確使用
使用.orOperator
組合broadcastTime
和planBroadcastTime
的條件,保持了預期的 OR 邏輯,避免生成無效結構。 -
避免沖突
修復后的查詢結構消除了格式錯誤,Spring Data MongoDB 能夠正確處理所有條件,不會觸發 “second ‘null’ criteria” 錯誤。
注意事項
-
測試驗證
應用修復后,建議使用不同的輸入組合(例如,提供startTime
和endTime
、僅提供startTime
、不同fallback
值)測試查詢,確保結果符合預期。 -
空值處理
確保StringUtil.isNotEmptyString
對null
和空字符串的處理符合預期,以避免意外添加條件。
總結
InvalidMongoDbApiUsageException
錯誤源于在同一字段的范圍查詢中誤用 .andOperator
,導致無效的 MongoDB 查詢結構。通過在每個字段的 Criteria
上直接鏈式調用 .lte()
和 .gte()
,并使用 .orOperator
組合不同字段的條件,可以構建正確的查詢。使用上述修復后的代碼即可解決問題。