Встроенный массив документов MongoDB: получите только один встроенный документ с атрибутом spezifi c - PullRequest
0 голосов
/ 01 августа 2020

Я хочу получить один встроенный документ с определенным полем (версией) c из массива с mongodb и Spring boot. Это структура данных:

{
   "_id": 5f25882d28e40663719d0b52,
   "versions": [
       {
           "versionNr": 1
           "content": "This is the first Version of some Text"
       },
       {
           "versionNr": 2
           "content": "This is the second Version of some Text"
       },
       ...
   ]
   ...
}

Вот мои сущности:

@Data
@Document(collection = "letters")
public class Letter {
  @Id
  @Field("_id")
  private ObjectId _id;
  
  @Field("versions")
  private List<Version> versions;
}

//There is no id for embedded documents 
@Data
@Document(collection = "Version")
public class Version{

  @Field("content")
  private String content;
  
  @Field("version")
  private Long version;
}

И это запрос, который не работает. Я думаю, что «присоединиться» неверно. Но не могу найти правильный путь.

public Optional<Version> findByIdAndVersion(ObjectId id, Long version) {
        Query query = new Query(Criteria.where("_id").is(id).and("versions.version").is(version));
        return Optional.ofNullable(mongoTemplate.findOne(query,Version.class,"letters"));
    }
}

РЕДАКТИРОВАТЬ: Это рабочая агрегация, я уверен, что это не очень хорошее решение, но оно работает

@Override
    public Optional<Version> findByIdAndVersion(ObjectId id, Long version) {

        MatchOperation match = new MatchOperation(Criteria.where("_id").is(id).and("versions.version").is(version));
        Aggregation aggregate = Aggregation.newAggregation(
                match,
                Aggregation.unwind("versions"),
                match,
                Aggregation.project()
                        .andInclude("versions.content")
                        .andInclude("versions.version")
        );

        AggregationResults<Version> aggregateResult = mongoTemplate.aggregate(aggregate, "letters", Version.class);
        Version version = aggregateResult.getUniqueMappedResult();
        return Optional.ofNullable(mongoRawPage);
    }

1 Ответ

1 голос
/ 01 августа 2020
Query query = new Query(Criteria.where("_id").is(id).and("versions.version").is(version));
return Optional.ofNullable(mongoTemplate.findOne(query,Version.class,"letters"));

Вы запрашиваете документ Letter, но ваш класс сущности указан как Version.class, поскольку findOne из MongoDB не возвращает субдокумент сам по себе, а, скорее, весь документ, вам необходимо иметь Letter.class в качестве возврата введите и отфильтруйте (проект), какие поля возвращать. Таким образом, вы можете спроецировать вложенный документ с единственной версией, который хотите получить, например:

Query query = new Query()
            .addCriteria(Criteria.where("_id").is(id).and("versions.version").is(version))
            .fields().position("versions", 1);
Optional.ofNullable(mongoTemplate.findOne(query, Letter.class))
        .map(Letter::getVersions)
        .findFirst()
        .orElse(null);

, или использовать конвейер агрегации:

newAggregation(
        Letter.class,
        match(Criteria.where("_id").is(id)),
        unwind("versions"),
        replaceRoot("versions"),
        match(Criteria.where("version").is(version))), 
    Version.class)

Примечание. Я набрал это на лету. .

...