Spring Data MongoDB Lookup с конвейерной агрегацией - PullRequest
0 голосов
/ 29 июня 2018

Как мне преобразовать следующий запрос MongoDB в запрос, который будет использоваться моим приложением Java Spring? Я не могу найти способ использовать pipeline с предоставленным методом lookup .

Вот запрос, который я пытаюсь преобразовать. Я также хочу отметить, что я не использовал $unwind, так как я хотел, чтобы deliveryZipCodeTimings оставался как сгруппированная коллекция в возвращаемом объекте.

db.getCollection('fulfillmentChannel').aggregate([
    {
        $match: {
            "dayOfWeek": "SOME_VARIABLE_STRING_1"
        }
    },
    {
        $lookup: {
            from: "deliveryZipCodeTiming",
            let: { location_id: "$fulfillmentLocationId" },
            pipeline: [{
                $match: {
                    $expr: {
                        $and: [
                            {$eq: ["$fulfillmentLocationId", "$$location_id"]},
                            {$eq: ["$zipCode", "SOME_VARIABLE_STRING_2"]}
                        ]
                    }
                }
            },
            { 
                $project: { _id: 0, zipCode: 1, cutoffTime: 1 } 
            }],
            as: "deliveryZipCodeTimings"
        }
    },
    {
        $match: {
            "deliveryZipCodeTimings": {$ne: []}
        }
    }
])

Ответы [ 2 ]

0 голосов
/ 06 июля 2018

Опираясь на информацию, предоставленную @dnickless, я смог решить эту проблему. Я опубликую полное решение в надежде, что оно поможет кому-то еще в будущем.

Я использую mongodb-драйвер: 3.6.4

Сначала мне нужно было создать собственный класс операции агрегирования, чтобы я мог передать собственный запрос JSON mongodb для использования в операции агрегации. Это позволит мне использовать pipeline в $lookup, который не поддерживается используемой версией драйвера.

public class CustomProjectAggregationOperation implements AggregationOperation {
    private String jsonOperation;

    public CustomProjectAggregationOperation(String jsonOperation) {
        this.jsonOperation = jsonOperation;
    }

    @Override
    public Document toDocument(AggregationOperationContext aggregationOperationContext) {
        return aggregationOperationContext.getMappedObject(Document.parse(jsonOperation));
    }
}

Теперь, когда у нас есть возможность передать пользовательский JSON-запрос в нашу реализацию mongodb spring, осталось только вставить эти значения в TypedAggregation запрос.

public List<FulfillmentChannel> getFulfillmentChannels(
    String SOME_VARIABLE_STRING_1, 
    String SOME_VARIABLE_STRING_2) {

    AggregationOperation match = Aggregation.match(
            Criteria.where("dayOfWeek").is(SOME_VARIABLE_STRING_1));
    AggregationOperation match2 = Aggregation.match(
            Criteria.where("deliveryZipCodeTimings").ne(Collections.EMPTY_LIST));
    String query =
            "{ $lookup: { " +
                    "from: 'deliveryZipCodeTiming'," +
                    "let: { location_id: '$fulfillmentLocationId' }," +
                    "pipeline: [{" +
                    "$match: {$expr: {$and: [" +
                    "{ $eq: ['$fulfillmentLocationId', '$$location_id']}," +
                    "{ $eq: ['$zipCode', '" + SOME_VARIABLE_STRING_2 + "']}]}}}," +
                    "{ $project: { _id: 0, zipCode: 1, cutoffTime: 1 } }]," +
                    "as: 'deliveryZipCodeTimings'}}";

    TypedAggregation<FulfillmentChannel> aggregation = Aggregation.newAggregation(
            FulfillmentChannel.class,
            match,
            new CustomProjectAggregationOperation(query),
            match2
    );

    AggregationResults<FulfillmentChannel> results = 
        mongoTemplate.aggregate(aggregation, FulfillmentChannel.class);
    return results.getMappedResults();
}
0 голосов
/ 29 июня 2018

Драйверы почти всегда немного отстают от текущих языковых возможностей, которые предоставляет MongoDB - следовательно, некоторые из последних и лучших функций просто недоступны через API. Боюсь, что это один из тех случаев, и вам придется прибегнуть к использованию строк. Вроде как так (не проверено):

AggregationOperation match = Aggregation.match(Criteria.where("dayOfWeek").is("SOME_VARIABLE_STRING_1"));
AggregationOperation match2 = Aggregation.match(Criteria.where("deliveryZipCodeTimings").ne([]));
String query = "{ $lookup: { from: 'deliveryZipCodeTiming', let: { location_id: '$fulfillmentLocationId' }, pipeline: [{ $match: { $expr: { $and: [ { $eq: ['$fulfillmentLocationId', '$$location_id']}, { $eq: ['$zipCode', 'SOME_VARIABLE_STRING_2']} ]} } }, { $project: { _id: 0, zipCode: 1, cutoffTime: 1 } }], as: 'deliveryZipCodeTimings' } }";
Aggregation.newAggregation(match, (DBObject) JSON.parse(query), match2);
...