#spring #mongodb #spring-boot
#spring #mongodb #spring-boot
Вопрос:
Извините за мой вопрос новичка, но я не могу в этом разобраться. Это моя коллекция:
[
{
_id: "A",
uuid: "12345",
version: 1,
test: "data1"
},
{
_id: "B",
uuid: "56566",
version: 1,
test: "data2"
},
{
_id: "C",
uuid: "12345",
version: 2,
test: "data3"
}
]
Я ищу запрос с условием UuidContains и с точным условием.
findByUuidContains(5)
-> Result: [B,C] as Object Array
findByUuidContains(12345)
-> Result: [C] as Object Array
findByUuidContains(66)
-> Result: [B]
Возможен ли такой запрос?
В словах:
Выберите все объекты, uuid которых содержит $ {value}, и из результирующего набора выберите только один для каждого uuid с самой высокой версией.
ПРАВКА1:
Я изменил проекцию группы из ответа:
db.collection.aggregate([
{
"$redact": {
"$cond": [
{
"$gt": [
{
"$indexOfCP": [
{
"$toLower": "$uuid"
},
"5"
]
},
-1
]
},
"$$KEEP",
"$$PRUNE"
]
}
},
{
$sort: {
version: -1
}
},
{
$group: {
_id: {
uuid: "$uuid"
},
version: {
$first: "$version"
},
id: {
$first: "$_id"
},
test: {
$first: "$test"
}
}
},
{
"$project": {
num: "1",
id: 1,
_id: 0,
version: 1,
test: 1
}
},
{
"$group": {
"_id": "$num",
"result": {
"$addToSet": {
id: "$id",
version: "$version",
test: "$test"
}
}
}
},
{
"$project": {
_id: 0,
result: 1
}
}
])
и я добавил некоторые атрибуты тестовых данных в свои документы. Теперь я должен «перевести» его на «язык» spring boot
ПРАВКА2:
В настоящее время я пытаюсь перевести второй ответ, но я не могу понять, как работает групповая операция в Spring. Кто-нибудь знаком с этим? Первая и вторая операции работают так же, как операции запроса mongo, но не удалось выполнить групповую операцию
String uuidRegexExp = String.format(".*%s.*", uuidSegment);
Pattern uuidPattern = Pattern.compile(uuidRegexExp);
MatchOperation match = new MatchOperation(Criteria.where("uuid").regex(uuidPattern));
SortOperation sort = Aggregation.sort(Sort.Direction.DESC,"version");
GroupOperation grup = Aggregation.group("version").first("version").as("version");
Aggregation aggregate = Aggregation.newAggregation(
match, sort, grup
);
AggregationResults<Example> aggregate1 = mongoTemplate.aggregate(aggregate, Example.COLLECTION_NAME, Example.class);
aggregate1.getMappedResults().forEach(er -> log.info(er.toString()));
Это пример класса:
@Data
@Document(Example.COLLECTION_NAME)
public class Example {
public static final String COLLECTION_NAME = "Example";
public static final String FIELD_UUID_NAME = "uuid";
public static final String FIELD_HOST_NAME = "host";
public static final String FIELD_URL_NAME = "url";
public static final String FIELD_VERSION_NAME = "version";
public static final String FIELD_ID_NAME = "_id";
@Field(FIELD_ID_NAME)
private ObjectId _id;
@Field(FIELD_UUID_NAME)
private String uuid;
@Field(FIELD_HOST_NAME)
private String host;
@Field(FIELD_URL_NAME)
private String url;
@Field(FIELD_VERSION_NAME)
private Long version;
}
ПРАВКА3:
Я думаю, что я это сделал. Вот код в не очень красивой версии:
String uuidRegexExp = String.format(".*%s.*", uuidSegment);
Pattern uuidPattern = Pattern.compile(uuidRegexExp);
MatchOperation match = new MatchOperation(Criteria.where("uuid").regex(uuidPattern));
SortOperation sort = Aggregation.sort(Sort.Direction.DESC,"version");
GroupOperation grup = Aggregation.group("uuid").first("version").as("version").first("_id").as("id");
ProjectionOperation project = Aggregation.project().and("_id").as("uuid").and("version").as("version").and("id").as("_id");
Aggregation aggregate = Aggregation.newAggregation(
match, sort, grup,project
);
AggregationResults<Example> aggregate1 = mongoTemplate.aggregate(aggregate, SingleRawArticle.COLLECTION_NAME, Example.class);
Комментарии:
1. Согласно вашей проблеме, findByUuidContains(5) -> Result: [B, C] поскольку массив объектов должен выдавать выходные данные как [A,B, C] , потому что A также содержит 5. Верно?
2. А ваше поле UUID является строковым или двойным?
3. Да, это проблема. Результатом будет [A, B, C] (потому что мой запрос неверен), но он должен быть [B, C] . UUID — это строка
4. Я добавил более короткий скрипт. Проверьте, поможет ли это вам
Ответ №1:
Это то, что вы ищете? Я создал для этого игровую площадку mongo. Вы можете проверить запрос, передав разные параметры. Я использовал 5
в примере, как показано ниже. Но я также пробовал с 12345
and 66
, и для меня это выглядит нормально.
{
"$indexOfCP": [
{
"$toLower": "$uuid"
},
"5"
]
},
Вот запрос :
db.collection.aggregate([
{
"$redact": {
"$cond": [
{
"$gt": [
{
"$indexOfCP": [
{
"$toLower": "$uuid"
},
"5"
]
},
-1
]
},
"$$KEEP",
"$$PRUNE"
]
}
},
{
$sort: {
version: -1
}
},
{
$group: {
_id: {
uuid: "$uuid"
},
version: {
$first: "$version"
},
id: {
$first: "$_id"
}
}
},
{
"$project": {
num: "1",
id: 1,
_id: 0
}
},
{
"$group": {
"_id": "$num",
"result": {
"$addToSet": "$id"
}
}
},
{
"$project": {
_id: 0,
result: 1
}
}
])
Комментарии:
1. Да! Это не совсем то, что я ищу, потому что мне нужны документы с отверстиями B и C, а не только _id. Я не был ясен в своем сообщении с самого начала. Это отличная работа, спасибо, я попробую и исправлю решение для документа с отверстиями на вашей игровой площадке.
Ответ №2:
проверьте приведенный ниже запрос, чтобы получить документы, соответствующие заданной строке. Я использовал регулярное выражение для сопоставления входной строки.
db.collection.aggregate(
[
{
"$match" : {
"uuid" : {
"$regex" : ".*5.*"
}
}
},
{
"$sort" : {
"version" : -1.0
}
},
{
"$group" : {
"_id" : {
"uuid" : "$uuid"
},
"uuid" : {
"$first" : "$uuid"
},
"id" : {
"$first" : "$_id"
},
"version" : {
"$first" : "$version"
}
}
},
{
"$project" : {
"_id" : "$id",
"uuid" : 1.0,
"version" : 1.0
}
}
],
{
"allowDiskUse" : false
}
);
Вывод:
{
"uuid" : "12345",
"version" : 2.0,
"_id" : "C"
}
{
"uuid" : "56566",
"version" : 1.0,
"_id" : "B"
}
Комментарии:
1. Ваше решение сопоставляет _id с uuid. Есть ли какая-либо причина, почему?
2. но тогда вам нужно спроецировать как первый ответ, чтобы получить исходный формат, или я ошибаюсь?
3. Да, вам нужно добавить этап проекта. Я изменил предыдущий запрос. Посмотрите. Модифицировал запрос, чтобы получить UUID с группового этапа, а затем спроецировать его в исходном формате
Ответ №3:
Java-код, эквивалентный запросу. Изменил редактирование в соответствии с последними изменениями. Изменены имена переменных, чтобы быть более конкретными.
String uuidRegexExp = String.format(".*%s.*", uuidSegment);
MatchOperation match = new MatchOperation(Criteria.where("uuid").regex(Pattern.compile(uuidRegexExp)));
SortOperation sort = Aggregation.sort(Sort.Direction.DESC,"version");
GroupOperation group = Aggregation.group("uuid").first("version").as("version").first("_id").as("id").first("uuid").as("uuid");
ProjectionOperation project = Aggregation.project().and("uuid").as("uuid").and("version").as("version").and("id").as("_id");
Aggregation aggregation = Aggregation.newAggregation(
match, sort, group,project
);
AggregationResults<Example> aggregate = mongoTemplate.aggregate(aggregation, SingleRawArticle.COLLECTION_NAME, Example.class);