我最近开始从事 Spring Boot 项目并选择 MongoDB 作为我的数据库。我有以下文档结构。
以下是用户文档结构。
@Data
@Builder(setterPrefix = "with")
@Document(collection = "users")
@JsonIgnoreProperties(value = {"password", "createdAt", "updatedAt"}, allowSetters = true)
public class User {
@Id
@Indexed
private String id;
@Indexed(unique = true, direction = IndexDirection.DESCENDING)
private String username;
private String name;
private String password;
@CreatedDate
private Date createdAt;
@LastModifiedDate
private Date updatedAt;
}
我的借用文档结构如下。
@Document(collection = "borrows")
@Data
@SuperBuilder(setterPrefix = "with")
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@AllArgsConstructor
@NoArgsConstructor
public abstract class Borrow {
@Id
@EqualsAndHashCode.Include
private String id;
@DocumentReference
private User borrower;
@DocumentReference
private User borowee;
private Date expectedReturnDate;
private Date actualReturnDate;
private String place;
private String occasion;
private BorrowStatus status;
public abstract String getType();
}
以及 Borrow 的两个子类如下。
借钱
@Document(collection = "borrows")
@Data
@EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true)
@SuperBuilder(setterPrefix = "with")
@BsonDiscriminator(key = "type", value = "Money")
public class BorrowMoney extends Borrow{
private Double amount;
@Override
public String getType() {
return "Money";
}
}
@Document(collection = "borrows")
@Data
@SuperBuilder(setterPrefix = "with")
@EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true)
@BsonDiscriminator(key = "type", value = "Items")
@AllArgsConstructor
@NoArgsConstructor
public class BorrowItem extends Borrow{
private String itemName;
private String description;
@Override
public String getType() {
return "Items";
}
}
提醒文档结构
@Data
@Builder
@Document(collection = "reminders")
public class Reminder {
@Id
private String id;
@DocumentReference
private Borrow borrow;
private String message;
private String header;
@Indexed
private String borrower;
@Indexed
private String borowee;
private boolean read;
@CreatedDate
private Date createdAt;
@LastModifiedDate
private Date updatedAt;
}
我正在尝试使用用户的 id 来获取当前登录用户的所有提醒。 我按照官方
spring-data-mongo
文档来理解属性表达式查询。
我在ReminderRepository中编写了以下方法。
@Repository
public interface ReminderRepository extends MongoRepository<Reminder, String> {
List<Reminder> findByBorrowBorrowerId(String id);
}
但是,尽管记录已经存在,但执行此操作始终返回 0 结果。
2024-03-30 17:05:26.998 DEBUG 27280 [nio-3080-exec-4,6607f8fe755cc27c4afe5cfe81fb8f8b,75158ed32fd3ebcc] o.s.d.m.c.MongoTemplate : find using query: { "borrow" : { "$oid" : "6605a6ea9796e7405763c9ac"}} fields: Document{{}} for class: class com.kitaab.hisaab.ledger.entity.Reminder in collection: reminders
我看到上面的查询是由
spring-data-mongo
生成的,这里的 id 6605a6ea9796e7405763c9ac
实际上是用户的而不是借用的。
根据文档,它应该采用属性路径borrow.borrower.id。
还尝试使用
@Query("{ 'borrow.borrower.id' : ?0 }}")
注释。然而,没有突破。
帮我解决这个问题。
存储库链接。
编辑1:
只是重现器代码
我不是 mongoDB 专家,但据我了解,Spring Data MongoDB 不支持直接使用 MongoRepository 接口查询嵌套字段(超过 2 个)。这是由于 MongoDB 处理文档之间引用的方式所致。
下面的代码返回结果
@Service
public class ReminderService {
@Autowired
private MongoTemplate mongoTemplate;
public List<Reminder> getRemindersByUserId(String userId) {
Query borrowQuery = new Query();
borrowQuery.addCriteria(Criteria.where("borrower.id").is(userId));
List<Borrow> borrows = mongoTemplate.find(borrowQuery, Borrow.class);
List<ObjectId> borrowIds = borrows.stream()
.map(Borrow::getId)
.collect(Collectors.toList());
Query reminderQuery = new Query();
reminderQuery.addCriteria(Criteria.where("borrow.id").in(borrowIds));
return mongoTemplate.find(reminderQuery, Reminder.class);
}
}
但是您可以更改现有的数据结构,不要深入采用继承方法,而使用
@DocumentReference
只需将所有内容分开并保留 id。例子
public class Reminder {
@Id
private ObjectId id;
private String borrowId;
private String borrowerId;
private String borroweeId;
private String message;
}
这样 mongoDB 将运行得更快,并且
MongoRepository
将按照您的预期进行响应。毕竟 mongodb 是一个文档数据库而不是 RDBMS。