搭一个新项目,从mongo数据库中查询数据,我直接使用的spring-data-mongodb模块。直接创建Repository接口,继承MongoRepository

public interface ResourceRepository extends MongoRepository<Resource, Long> {
}

使用MongoRepository的findById方法,查询"_id"为某个值,程序中查询不出来,但是数据库中有值。并且使用db.getCollection(‘resource’).find({"_id":})验证过。
然后查询的时候debug了下,走到了MongoTemplate的findById方法中,它将_id替换为了id:

public <T> T findById(Object id, Class<T> entityClass, String collectionName) {

        Assert.notNull(id, "Id must not be null!");
        Assert.notNull(entityClass, "EntityClass must not be null!");
        Assert.notNull(collectionName, "CollectionName must not be null!");

        MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entityClass);
        String idKey = ID_FIELD;//_id

        if (persistentEntity != null) {
            if (persistentEntity.getIdProperty() != null) {
                idKey = persistentEntity.getIdProperty().getName();//赋值为id
            }
        }

        return doFindOne(collectionName, new Document(idKey, id), new Document(), entityClass);
    }

idKey = persistentEntity.getIdProperty().getName();这句代码把“_id”的key换为了“id”,这样如果mongo集合中只有“_id”字段,就查询不出来了。

解决方案

继承MongoTemplate类,重写它的findById方法,我Debug后MongoTemplate执行的是public MongoTemplate(MongoDbFactory mongoDbFactory, @Nullable MongoConverter mongoConverter) 的构造方法:MongoRepository的findById方法查不出_id值的解决方案.md
我们也创建类似的构造方法:

@Component
public class PMongoTemplate extends MongoTemplate{
    private static final String ID_FIELD = "_id";
    
    @Autowired
    public PMongoTemplate(MongoDbFactory mongoDbFactory, @Nullable MongoConverter mongoConverter) {
        super(mongoDbFactory,mongoConverter);
    }
    
    @Override
    public <T> T findById(Object id, Class<T> entityClass, String collectionName) {

        Assert.notNull(id, "Id must not be null!");
        Assert.notNull(entityClass, "EntityClass must not be null!");
        Assert.notNull(collectionName, "CollectionName must not be null!");
        String idKey = ID_FIELD;
        return doFindOne(collectionName, new Document(idKey, id), new Document(), entityClass);
    }
}

启动之后报如下错误,没有创建Bean ‘mongoTemplate’:

因为我们自定了一个MongoTemplate类型的Bean,所以Spring在初始化的时候,不不再创建同一类型的了。所以我们之前创建的ResourceRepository等接口都无法使用了,这些接口继承MongoRepository,启动后创建对应的SimpleMongoRepository,SimpleMongoRepository间接依赖了mongoTemplate。

这样走不通,那我们就用MongoTemplate自带的方法:

protected <T> T doFindOne(String collectionName, Document query, Document fields, Class<T> entityClass) {

        MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
        Document mappedQuery = queryMapper.getMappedObject(query, entity);
        Document mappedFields = queryMapper.getMappedObject(fields, entity);

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("findOne using query: {} fields: {} for class: {} in collection: {}", serializeToJsonSafely(query),
                    mappedFields, entityClass, collectionName);
        }

        return executeFindOneInternal(new FindOneCallback(mappedQuery, mappedFields),
                new ReadDocumentCallback<T>(this.mongoConverter, entityClass, collectionName), collectionName);
    }

@Nullable
    @Override
    public <T> T findOne(Query query, Class<T> entityClass, String collectionName) {

        Assert.notNull(query, "Query must not be null!");
        Assert.notNull(entityClass, "EntityClass must not be null!");
        Assert.notNull(collectionName, "CollectionName must not be null!");

        if (ObjectUtils.isEmpty(query.getSortObject()) && !query.getCollation().isPresent()) {
            return doFindOne(collectionName, query.getQueryObject(), query.getFieldsObject(), entityClass);
        } else {
            query.limit(1);
            List<T> results = find(query, entityClass, collectionName);
            return results.isEmpty() ? null : results.get(0);
        }
    }

doFindOne是protected修饰的我们无法直接调用,findOne可以调用,我们只需要创建Query对象,将条件传递进去即可,下面是简单的实现:

@Component
public class MongoQLService {

    @Autowired
    MongoTemplate mongoTemplate;
    
    
    public <T>  T findById(Object id,Class<T> entityClass,String collectionName) {
        Query query  = new Query();
        query.addCriteria( new Criteria("_id").is(id));
        return  mongoTemplate.findOne(query, entityClass, collectionName);
    }
}

关于Query的构建,参考Spring Data MongoDB 基本文档查询

相关文章:

  • 2022-03-07
  • 2021-08-15
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2021-11-22
  • 2022-12-23
  • 2022-03-06
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案