web-dev-qa-db-fra.com

Spring Data MongoDB Lookup avec Pipeline Aggregation

Comment pourrais-je convertir la requête MongoDB suivante en requête à utiliser par mon Java Spring? Je ne trouve pas un moyen d'utiliser pipeline avec le recherche méthode.

Voici la requête que j'essaie de convertir. Je veux également noter que je n'ai pas utilisé $unwind car je voulais que deliveryZipCodeTimings reste en tant que collection groupée dans l'objet de retour.

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: []}
        }
    }
])
4
Always Learning

Sur la base des informations fournies par @dnickless, j'ai pu résoudre ce problème. Je publierai la solution complète dans l'espoir qu'elle aide quelqu'un d'autre à l'avenir.

J'utilise mongodb-driver: 3.6.4

Tout d'abord, j'ai dû créer une classe d'opération d'agrégation personnalisée afin de pouvoir passer une requête mongodb JSON personnalisée à utiliser dans l'opération d'agrégation. Cela me permettra d'utiliser pipeline dans un $lookup qui n'est pas pris en charge avec la version du pilote que j'utilise.

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));
    }
}

Maintenant que nous avons la possibilité de passer une requête JSON personnalisée dans notre implémentation mongodb spring, il ne reste plus qu'à brancher ces valeurs dans une requête 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();
}
6
Always Learning

Les pilotes sont à peu près toujours un peu en retard sur les fonctionnalités de langage actuelles fournies par MongoDB - par conséquent, certaines des dernières et meilleures fonctionnalités ne sont tout simplement pas bien accessibles via l'API. Je crains que ce soit l'un de ces cas et vous devrez recourir à l'utilisation de chaînes. Un peu comme ça (non testé):

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);
2
dnickless