Morphia Aggregation Pipeliene - mongodb

I need a little help with an aggregation pipeline in morphia. This is what I have in mongo:
db.transacciones.aggregate([
{$match:
{"$and":[
{"usuario._id": "xxx#gmail.com"},
{"status":{"$ne":"ERROR"}}]}},
{$sort:{"date": -1}},
{$group:{"ordenId", "transaction" : {$first:"$$ROOT"}}},
{$replaceRoot:{newRoot:"$transaction"}}])
Ok, this is what I have in morphia:
Query<TransaccionP2P> match = ds.getQueryFactory().createQuery(ds);
match.and(match.criteria("usuario._id").equal(usuarioId),
match.criteria("status").notEqual(Status.ST_ERROR));
Sort sort = Sort.descending("date");
Group group = grouping("transaction", Accumulator.accumulator("$first", (Object)"$$ROOT"));
Projection[] projections = {
Projection.projection("_id", "$transaction._id"),
...
};
AggregationPipeline pipeline = ds.createAggregation(TransaccionP2P.class)
.match(match)
.sort(sort)
.group("orden._id", group)
.project(projections);
Iterator<TransaccionP2P> iterator = pipeline.aggregate(TransaccionP2P.class);
List<TransaccionP2P> transacciones = new ArrayList<>();
iterator.forEachRemaining(transacciones::add);
I have managed to construct this pipeline with the stackoverflow articles I found because I couldn't find a good example in Morphia documentation but I have these problems:
Morphia doesn't seem to have support for $replaceRoot so I have to create the projection field by field.
The transaction variable in the group aggregate is not recognized in the projection step.
Here is the projection exception:
com.mongodb.MongoCommandException: Command failed with error 17276: 'Use of undefined variable: transaction'.
I haven't managed to find the correct way of making the projection for 'transaction' to be recognized.
Can you help me?
Thanks

Related

How to filter on collection in deployment level changestream in mongodb java sdk

I am trying to setup a deployment level change stream with a pipeline filter on collection name using MongoDB java SDK. Here is the code snippet.
List<Bson> pipeline = Collections.singletonList(Aggregates.match(Filters.or(
Filters.eq("namespace", "db1.c1"),
Filters.eq("namespace", "db1.c2"))));
client.watch(pipeline)
.cursor()
.forEachRemaining(doc -> {
System.out.println(doc);
});
But this query does not match any document. Following variations of the pipeline document does not work either.
List<Bson> pipeline =
Collections.singletonList(Aggregates.match(Filters.or(
Document.parse("{'namespace': 'db1.c1'}"),
Document.parse("{'namespace': 'db1.c2'}"))));
Surprisingly pipeline works on other fields of the changestream document. For example, this works:
List<Bson> pipeline = Collections
.singletonList(Aggregates.match(Filters.and(
Document.parse("{'fullDocument.seq': 4}"),
Filters.in("operationType", Arrays.asList("insert")))));
I am not sure why this would be the case. I would appreciate any help in this regard.
in Order to get changestream events on DB or collection level you need to use filters on below attributes :
ns.db The name of the database.
ns.coll The name of the collection.
In your case if you are interested only for collection C1 & c2 then consider having filter something like below.
List<Bson> pipeline = Collections.singletonList(Aggregates.match(Filters.or(
Filters.eq("ns.coll", "c1"),
Filters.eq("ns.coll", "c2"))));
client.watch(pipeline)
.cursor()
.forEachRemaining(doc -> {
System.out.println(doc);
});
Please Note: above filter is on collections only you can add filter on DB for collection form specific DB like (ns.db = "db1" AND
ns.coll : $in :["c1", "c2"] )
MongoDB doc reference: https://docs.mongodb.com/manual/reference/change-events/#change-stream-output

Spring Data Mongo - Custom AggregtionOption not working

I tried creating a Custom AggregationOperation based on https://github.com/krishnaiitd/learningJava/tree/master/spring-boot-sample-data-mongodb
When I used a custom aggregation in my aggregation for a lookup, it threw an exception saying the "as" field is not found on the entity.
If anybody has tried using custom AggregationOperation please share your code or let me know where I am going wrong.
Below is my code,
String lookup = "{ $lookup : { from: 'ITEM', localField : 'item_id', foreignField : '_id', as : 'item' } }";
TypedAggregation<Order> aggregation = Aggregation.newAggregation(Order.class,
new CustomAggregationOperation(lookup),
unwind("item", false));
The exception:
org.springframework.data.mapping.PropertyReferenceException: No property item found for type Order!
A TypedAggregation is a special Aggregation that holds information of the input aggregation type.
https://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/core/aggregation/TypedAggregation.html
That means that Spring will verify after each stage that your documents have not changed the structure.
Since you are trying transform original document, you need to use a standard Aggregation.
Aggregation aggregation = Aggregation.newAggregation(
new CustomAggregationOperation(lookup),
unwind("item", false)
);
List<Order> result = mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(Order.class), Order.class).getMappedResults();

Meteor Mongo find with filter options

I would like to run a mongo find but also have it filter. $and makes every object required and $or shows results for any of the matching object but still does not filter.
This is my current query
var query = {
organizationId:user.organizationId,
formName: this.props.formName,
$or:[
{producerId:this.props.producerId},
{blockId:this.props.blockId},
{created:{$gte:new Date(this.props.startDate), $lt:new Date(this.props.endDate)}}
]};

full text search with and condition

Is it possible to include AND, OR, NOTIN conditions with text search in MongoDB?
e.g.
final DBObject textSearchCommand = new BasicDBObject();
textSearchCommand.put("text", "user");
textSearchCommand.put("search", fullTextSearch.text)
textSearchCommand.put("isDeleted", false)\\ this is AND condition here, but this does not work
final CommandResult commandResult = db.command(textSearchCommand);
Is there any work around for this ?
You have not maintained it clearly that do you want AND operation for all fields or you want first two fields in OR Operation and last fields i.e isDeleted is in AND operation with first two.
I'm considering you want All Three Fields in AND Operation
You case use AND , OR operator in mongodb to query on full text.
NOTIN i.e. $nin operator you have to use with particular field.
Below is code with $and operator in mongodb
final BasicDBList textSearchCommand = new BasicDBList();
/* List is used to add element */
textSearchCommand.add( new BasicDBObject("text", "user"));
textSearchCommand.add( new BasicDBObject("search", fullTextSearch.text));
textSearchCommand.add( new BasicDBObject("isDeleted", false));
BasicDBObject queryDoc = new BasicDBObject("$and", textSearchCommand);
/* Above Statement Adds and operator to query */
final CommandResult commandResult = db.command(queryDoc);
You can use $or same as like $and.
NotIn operator i.e. $nin used with particular field.
Following Are the links you can use reference.
And Operator : $and
OR Operator : $or
NOTIN Operator : $nin

Comparison operator for the computed count value in MongoDB Aggregation Pipeline

I am using Aggregation Pipeline concept and below is the Java code which I used.
DBObject match = new BasicDBObject("$match",
new BasicDBObject("field_name", "value"));
DBObject group = new BasicDBObject("$group",
new BasicDBObject("_id" , "")
.append("count", new BasicDBObject("$sum", 1)));
The first pipeline operator "$match" will filter out documents. The second pipeline operator "$group" will give out the number of documents in the collection (In the above example). Let us say, the third pipeline operator is $project.
List<DBObject> pipeline = Arrays.asList(match, group, project);
AggregationOutput output = users.aggregate(pipeline);
The operation which I want to perform goes like this - I want to use $gte operator for the computed count value ( E.g., if { count : { $gte : 5 } } then continue to $project else exit).
Could anyone please help me out in solving this problem.
Use two queries: a count(), a check for the threshold, then a find() with a projection if necessary. You can't terminate the aggregation early based on some condition, as far as I know, so while I think you could construct a pipeline to quasi-fit your demands, really you should do the most natural thing. In the mongo shell since I don't have the Java driver handy to test with:
> var t = db.test.count({ "field" : "value" })
> if (t > 5) {
results = db.test.find({ "field" : "value"}, projection)
}
It's hard to give good code for this without knowing more about what your greater objective is.
I think you can use $match again as the third pipeline operator instead, link this: DBObject match2 = BasicDBObjectBuilder.start().push("$match").push("count").append("$gte", 5).get();