MongoDB Java get Schema of existing collection using aggregation - mongodb

I am looking for solutions to get field name and type for all nested fields including array of documents using $project $mergeobjects, $objectToArray , $unwind.
collection.aggregate(Arrays.asList(
new Document("$limit",100),
new Document("$project", new Document("fields", new Document("$objectToArray", "$ROOT" ))),
new Document("$unwind", "$fields"),
new Document("$project", new Document("fields", new Document("k", "$fields.k").append("v",new Document("$type", "$fields.v")))),
new Document("$group", new Document("_id", "$fields.k").append("fields", new Document("$first", "$fields"))),
new Document("$group", new Document("_id", null).append("fields", new Document("$push", "$fields"))),
new Document("$project", new Document("fields", new Document("$arrayToObject", "$fields" )))
));
I have tried implementing but could not process array of documents yet. I am trying to learn how to use $mergeObjects to achieve the output

Related

$lookup is applied again on all subfields of a looked up object

I'm using Spring Data MongoDB and applying $lookup on a field with ObjectId value,
what I'm getting is the referenced document like I want but also the fields of that document are also populated, $lookup is applied again on the fields of the referenced document which causes the query to take a very long time to execute (around 5mins).
The query works fine using a raw query from a mongo client without spring data MongoDB, the lookup is applied only once and I get a document that has ObjectId value in the fields instead of those fields being populated too.
This is the raw query
{$match : {_id : new ObjectId("63282356bb1b311dd0e63f67")}},
{$lookup : {
"from":"paper",
"let":{
"userId":"$_id"
},
"pipeline":[
{$facet:{
sent:[
{$match:{
"$expr":{"$eq":["$to", "$$userId"]}
}}
],
}}
],
"as":"papers"
}}
])
And I'm translating this to spring data mongodb like this
Aggregation aggregation = Aggregation.newAggregation(
matchStage,
aggregationOperationContext -> {
Document lookupPipeline = new Document("$lookup",
new Document("from", "paper")
.append("let", new Document("userId", "$_id"))
.append("pipeline", Arrays.<Object> asList(
new Document("$facet",
new Document("sent",Arrays.<Object>asList(
new Document("$match", new Document("$expr",
new Document("$eq", Arrays.<Object>asList("$to", "$$userId"))
))
)
)
)
))
.append("as", "papers")
);
return aggregationOperationContext.getMappedObject(lookupPipeline);
}
);
I'm using the custom aggregation because using $lookup with the pipeline field is not supported in spring data MongoDB as of now
Also I'm using #DocumentReference
public class User{
#ReadOnlyProperty
#DocumentReference
private List<Paper> papers;
}

Mongo DB Java 3.x Driver - Group By Query

I'd like to learn how to implement group by query using Mongo DB Java 3.x Driver. I want to group my collection through the usernames, and sort the results by the count of results DESC.
Here is the shell query which I want to implement the Java equivalent:
db.stream.aggregate({ $group: {_id: '$username', tweetCount: {$sum: 1} } }, { $sort: {tweetCount: -1} } );
Here is the Java code that I have implemented:
BasicDBObject groupFields = new BasicDBObject("_id", "username");
// count the results and store into countOfResults
groupFields.put("countOfResults", new BasicDBObject("$sum", 1));
BasicDBObject group = new BasicDBObject("$group", groupFields);
// sort the results by countOfResults DESC
BasicDBObject sortFields = new BasicDBObject("countOfResults", -1);
BasicDBObject sort = new BasicDBObject("$sort", sortFields);
List < BasicDBObject > pipeline = new ArrayList < BasicDBObject > ();
pipeline.add(group);
pipeline.add(sort);
AggregateIterable < Document > output = collection.aggregate(pipeline);
The result I need is the count of documents grouped by username. countOfResults returns the total number of the documents the collection has.
You should try not to use old object (BasicDBObject) types with Mongo 3.x. You can try something like this.
import static com.mongodb.client.model.Accumulators.*;
import static com.mongodb.client.model.Aggregates.*;
import static java.util.Arrays.asList;
Bson group = group("$username", sum("tweetCount", 1));
Bson sort = sort(new Document("tweetCount", -1));
AggregateIterable <Document> output = collection.aggregate(asList(group, sort));

Mongo DB regex aggregation query using java API

I want to query using regex and aggregation in mongo db, the following is working fine in mongo shell but how to write the same using Java API.
db.posts_collection.aggregate({$unwind:"$posts"},
{$match :{"posts.message":/.*keyword.*/} })
I tried using the following but unable to get the required result,
BasicDBObject unwind = new BasicDBObject("$unwind","$posts");
BasicDBObject matchKeyWord = new BasicDBObject("$match",new
BasicDBObject("posts.message",java.util.regex.Pattern.compile("keyword")));
AggregationOutput output = collection.aggregate(unwind,matchKeyWord);
Please tell me how to write the same query in java.
I would think that should work, but if you really wanted to be sure use the $regex operator form instead:
BasicDBObject unwind = new BasicDBObject("$unwind","$posts");
BasicDBObject matchKeyWord = new BasicDBObject(
"$match",new BasicDBObject(
"posts.message",new BasicDBObject("$regex",".*keyword.*")
)
);
AggregationOutput output = collection.aggregate(unwind,matchKeyWord);
That operator exists for the purpose of "safe" serialization with differing drivers.

mongodb java aggregate return empty result

i need to use mongodb java aggregate function to detect duplicated documents in collection, this is the query i ran from command line and it worked:
db.placements.aggregate(
{$group:{ "_id: "$campaign", total:{$sum:1}}},
{$match: {total: {$gt:2}}},
{$limit:10},
{$skip:0}
);
and this is the java code i wrote:
DBObject groupFields = new BasicDBObject("_id", "$campaign");
groupFields.put("total", new BasicDBObject("$sum", 1));
DBObject group = new BasicDBObject("$group", groupFields);
DBObject matchFields = new BasicDBObject("total", new BasicDBObject("$gt", 2));
DBObject match = new BasicDBObject("$match", matchFields);
collection.aggregate(match, group, new BasicDBObject("$skip", 0), new BasicDBObject("$limit", 10));
but it always return empty result. can anyone tell me what's wrong?

mongodb java to insert embedded document

I have a collection with embedded documents in it.
System
{
System_Info: ...,
Tenant: [
{
Tenant_Id: ...,
Tenant_Info: ...,
Prop_Info: ...
},
{
Tenant_Id: ...,
Tenant_Info: ...,
Prop_Info: ...
} ]
}
If I need to insert another tenant information like this
Tenant { Tenant_Id:2,Tenant_Info:"check",prop_info:"client"}.
whats the mongodb query to insert embedded documents? and how to do it using java?
Use the following code to insert into array :
BasicDBObject query = new BasicDBObject();
query.put( "System_Info", "...." );
BasicDBObject tenant = new BasicDBObject();
tenant.put("Tenant_Id", 2);
tenant.put("Tenant_Info", "check");
tenant.put("Prop_Info", "client");
BasicDBObject update = new BasicDBObject();
update.put("$push", new BasicDBObject("Tenant",tenant));
coll.update(query, update,true,true);
Are you trying to add another Tenant into the array? If so, you would want to create a DBObject representing the Tenant, and then $push it onto the array.
In Java, embedded documents are represented by DBObjects (of which BasicDBObject is a subclass). Here is an example of inserting an embedded document, from the docs:
http://www.mongodb.org/display/DOCS/Java+Tutorial#JavaTutorial-InsertingaDocument
Additionally, here is an example of using $push in Java:
Updating an array in MongoDB using Java driver
...and this is how to do it with mongo-driver version >= 3.1 (mine is 3.2.2):
Document tenant = new Document("Tenant_Id", 2)
.append("Tenant_Info", "check")
.append("Prop_Info", "client");
Bson filter = Filters.eq( "System_Info", "...." ); //get the parent-document
Bson setUpdate = Updates.push("Tenant", tenant);
coll.updateOne(filter, setUpdate);
Hope that helps someone.