I want to count the number of videos in each mediaList and then return the total number of videos in the document.
{
_id: ObjectId("5f9d8d02d7bb2c56b678614c"),
mainTopicId: "5f8066dad0b65b3b9ca67e4b",
subTopicId: "5f9d89f5d7bb2c56b678614b",
userIdLiked: [
"5fe4560f19050e372a2a17f8",
"5f8061e0d0b65b3b9ca67e49"
],
likeCount: NumberInt(2),
mediaList: [
{
url: "ad491eb8-7f28-47da-9d35-fe83bb4f8eb0.mp4",
mediaType: "VIDEO"
}
],
text: "this sample text",
title: "sample title",
created: ISODate("2020-10-31T16:12:50.615Z"),
updated: ISODate("2020-10-31T16:12:50.615Z"),
},
{
_id: ObjectId("5f9d8f95d7bb2c56b678614e"),
mainTopicId: "5f8066dad0b65b3b9ca67e4b",
subTopicId: "5f67816fb2ae8c3e1f203946",
userIdLiked: [
"5f8061e0d0b65b3b9ca67e49"
],
mediaList: [
{
url: "5633c4b2-d3aa-4d7c-8419-1403e43674b1.mp4",
mediaType: "VIDEO"
}
],
text: "sample text 2",
title: "sample title 2",
created: ISODate("2020-10-31T16:23:49.488Z"),
updated: ISODate("2020-10-31T16:23:49.488Z"),
_class: "com.example.api.pregnancy.models.Content"
}
I use this Spring-boot code for sum likeCount in document.
now i want count total mediaType when is VIDEO type
Aggregation agg = Aggregation.newAggregation(
project("subTopicId").and("likeCount").as("sumLikeCount"),
group("subTopicId").sum("sumLikeCount").as("totalCount")
);
The code
Aggregation aggregation = Aggregation.newAggregation(
p-> new Document("$project",
new Document("totalVideos",
new Document("$size",
new Document("$filter",
new Document("input","$mediaList").append("cond",
new Document("$eq",Arrays.asList("$$this.mediaType","VIDEO"))
)
)
)
)
)
).withOptions(AggregationOptions.builder().allowDiskUse(Boolean.TRUE).build());
Spring-data doesn't provide few operation like $addFields, $filter. So what we can do is to go with a trick using BSON
Note : This code is not tested, Hope, it would work. It was written based on working Mongo playground
Related
I have the following document in mongodb:
{
"_id":"43434",
"mail": "test#gmail.com"
"category": ["Alimentari","Eventi","Ristorante","Servizi"]
}
I would like to write java code so that if:
I have the following Array of string in input ["Alimentari","Eventi","Ristorante"], the document remain unchanghed
with the following array string ["Alimentari","Bar"] the document will be:
{
"_id":"43434",
"mail": "test#gmail.com"
"category": ["Alimentari","Eventi","Ristorante","Servizi","Bar"]
}
if I pass an array of just one string ["Alimentari"], the document remain unchanghed
if I pass the following ["Grande Distribuzione"], the document will be
{
"_id":"43434",
"mail": "test#gmail.com"
"category": ["Alimentari","Eventi","Ristorante","Servizi","Grande Distribuzione"]
}
I tried with this code
String[] category= {"Alimentari","Eventi","Ristorante"};
collection.updateOne(
new BasicDBObject("_id", new ObjectId(_id)),
new BasicDBObject("$set", new BasicDBObject("category", category));
but the resulting document is:
{
"_id":"43434",
"mail": "test#gmail.com"
"category": ["Alimentari","Eventi","Ristorante"]
}
Could you please help me ?
Thank you
For MongoDB query answer, you need $addToSet with $each to add multiple values into the category field if the value doesn't exist.
db.collection.update({
_id: "43434"
},
{
"$addToSet": {
"category": {
"$each": [
"Alimentari",
"Bar"
]
}
}
})
Sample Mongo Playground
How to project embedded array element field in Spring Data MongoDB Aggregation with the document sample below, I tried:
project("customers.id")
project("customers.[].id")
project("customers.?.id")
project("$customers.id")
but didn't work.
Result document without projection:
{
"id": "group1",
"name": "Default Identity Management",
"warningThreshold": 900000,
"tariffId": "TR_0001",
"active": false,
"customers": [
{
"id": "1",
"name": "David",
"properties": [
{
"name": "phone",
"value": "678"
}
],
"roles": [
"dev"
]
},
{
"id": "2",
"name": "Peter",
"properties": [
{
"name": "phone",
"value": "770"
}
],
"roles": [
"techsales",
"dev"
]
}
]
}
Expected document like this:
{
"id" : "group1",
"name" : "Group1",
"tariffId" : "TR_0001",
"warningThreshold" : 900000,
"customers" : [
{
"id" : "1",
"name" : "David",
"properties" : [
{
"name" : "phone",
"value" : "678"
}
]
},
{
"id" : "2",
"name" : "Peter",
"properties" : [
{
"name" : "phone",
"value" : "770"
}
]
}
]
}
I would like to include customers[].id, customers[].name, customers[].properties.
I'd been trying to figure this out for a while now, but couldn't. And the other posts here on stackoverflow, and other places on the internet, didn't provide the solution I was looking for.
My problem was similar to the original author's: There's a document, which has a field which is an array of documents. I wanted to query all the top level fields in the document, and exclude a single field from the documents within the array.
s7vr's answer in the comments for the question did the job for me! Just re-posting that here since most people don't go through all the comments, and it is a really useful answer, that saved me from writing a lot of crappy code! :D
AggregationOperation project = new AggregationOperation() {
#Override
public Document toDocument(AggregationOperationContext aggregationOperationContext) {
return new Document("$project", new Document("arrayField.nestedFieldToExclude", 0));
}
};
With Lambda:
AggregationOperation project = aggregationOperationContext -> new Document("$project", new Document("arrayField.nestedFieldToExclude", 0));
Overall pipeline:
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(criteria),
Aggregation.sort(Sort.Direction.DESC, "createdOn"),
project);
I just wish there was a cleaner way to do this with the Spring MongoDB Data API directly, rather than using it this way with lambda functions.
Also, please note that the method AggregationOperation.toDocument(AggregationOperationContext aggregationOperationContext) has been deprecated as of spring-data-mongodb version 2.2.
Here is the code :
AggregateIterable<Document> result = chatLogCollection.aggregate(Arrays.asList(
new Document("$match", new Document("displayName", "user")),
new Document("$group", new Document("_id","$sessionGUID")
.append("time", new Document("$first","$ts"))
.append("makerID", new Document("$first","$makerID"))),
new Document("$sort", new Document("time", -1)),
new Document("$skip", skip),
new Document("$limit", limit)
));
This will generate the below type out put.
{
"displayName": "test test",
"_id": "123a54be-4b69-cd49-edb3-9b264fea077b",
"time": {
"$date": 1499759619016
},
"makerID": "xxxxx"
}
I need to format this to look like this:
{
"displayName": "test test",
"sessionID": "123a54be-4b69-cd49-edb3-9b264fea077b",
"time": {
"$date": 1499759619016
},
"makerID": "xxxxx"
}
That means i need to appear _id as sessionId. Please help me to do that.I am using mongoDB, java and windows 7.
I am using Core reporting API (V4) through java to extract data with custom dimension.
There are two Scenarios. One in which i use two dimensions (pagePath and hostname) and in another i use just one dimension (pagePath only).
Issue is that i am observing difference in both requests. On using one dimension, data is exact copy of what I See on GA Dashboard. But on using two dimensions, This data i receive is not conforming with DA Dashboard.
Refer Code below -
DateRange dateRange = new DateRange();
dateRange.setStartDate("2016-08-01");
dateRange.setEndDate("2016-08-01");
Metric sessions = new Metric().setExpression("gaSmiley Tongueageviews").setAlias("PageViews");
Metric avgtime = new Metric().setExpression("ga:timeOnPage").setAlias("Time On Page");
List<Metric> list = new ArrayList<Metric>();
list.add(sessions);
list.add(avgtime);
Dimension dimension1 = new Dimension().setName("gaSmiley TongueagePath");
Dimension dimension2 = new Dimension().setName("ga:hostname");
List<Dimension> listd = new ArrayList<Dimension>();
listd.add(dimension1);
listd.add(dimension2); //---Error Occurs on Addition of this
List<DimensionFilter> filterList = new ArrayList<DimensionFilter>();
DimensionFilter dimFilter = new DimensionFilter().setDimensionName("gaSmiley TongueagePath").setOperator("REGEXP")
.setExpressions(Arrays.asList("53474130"));
filterList.add(dimFilter);
DimensionFilterClause clause = new DimensionFilterClause().setFilters(filterList);
clause.setFilters(filterList);
List<GetReportsResponse> responseList = new ArrayList<GetReportsResponse>();
String pageToken = "";
while(pageToken != null){
ReportRequest request = new ReportRequest().setViewId(VIEW_ID).setDateRanges(Arrays.asList(dateRange))
.setDimensions(listd).setMetrics(list).setDimensionFilterClauses(Arrays.asList(clause));
System.out.println(request);
if(pageToken != null && !pageToken.isEmpty()){
request.setPageToken(pageToken); }
ArrayList<ReportRequest> requests = new ArrayList<ReportRequest>();
requests.add(request);
GetReportsRequest getReport = new GetReportsRequest().setReportRequests(requests);
GetReportsResponse response = service.reports().batchGet(getReport).execute();
System.out.println(response);
responseList.add(response);
pageToken = response.getReports().get(0).getNextPageToken();
break;
}
When ever I use "dimension2" in query Data comes out to be (3 records, whose data is different from what I see on dashboard)-
{
"dimensions": ["m.photos.timesofindia.com/celebs/celeb-themes/celebs-at-airport/articleshow/53474130.cms",
"m.photos.timesofindia.com"],
"metrics": [{
"values": ["12",
"19.0"]
}]
}{
"dimensions": ["m.photos.timesofindia.com/celebs/celeb-themes/celebs/celeb-themes/celebs-at-airport/articleshow/53474130.cms",
"m.photos.timesofindia.com"],
"metrics": [{
"values": ["231",
"698.0"]
}]
}{
"dimensions": ["photogallery.indiatimes.com/celebs/celeb-themes/celebs-at-airport/articleshow/53474130.cms",
"photogallery.indiatimes.com"],
"metrics": [{
"values": ["168",
"648.0"]
}]
}
But When i re-run my code without the "hostname" dimension, Data i see is conforming with what is visible on dashboard. Response in this case is -
{
"dimensions": ["m.photos.timesofindia.com/celebs/celeb-themes/celebs/celeb-themes/celebs-at-airport/articleshow/53474130.cms"],
"metrics": [{
"values": ["217",
"746.0"]
}]
}{
"dimensions": ["photogallery.indiatimes.com/celebs/celeb-themes/celebs-at-airport/articleshow/53474130.cms"],
"metrics": [{
"values": ["181",
"2031.0"]
}]
}
Current Core Reporting API version used is V4.
I have tried sampling also. But there was no difference is response.
I am seeing difference in data once i add "hostname" dimension.
Please help me out here.
Warm Regards,
Vibhav
Okey, let's start. Imagine that we have the next mongo collection:
{
"city": "TWENTYNINE PALMS",
"loc": [-116.06041, 34.237969],
"pop": 11412,
"state": "CA",
"_id": "92278"
}
{
"city": "NEW CUYAMA",
"loc": [-74.823806, 34.996709],
"pop": 80,
"state": "CA",
"_id": "93254"
}
{
"city": "WATERBURY",
"loc": [-72.996268, 41.550328],
"pop": 25128,
"state": "CT",
"_id": "06705"
}
Notice that loc array is [latitude,longitude]
I would like to obtain using java mongo driver the "pop" average of the cities that have the altitude beetwen -75,-70.
So, using SQL I know that the query is:
SELECT avg(pop)
WHERE loc.altitude > -75 AND lloc.altitude < -70
I am very noob in mongodb, this is my current code:
BasicDBObject doc = new BasicDBObject("loc.0", new BasicDBObject("$gte",
-75).append("$lte", -70));
DBCursor cursor = collection.find(doc);
The previous code returns me all the documents that altitude are beetwen (-75,-70), but I do not know how to obtain the average,using mongo driver, I know that I can iterate over results using java..
Thank you
Use the aggregation framework with following aggregation pipeline (Mongo shell implementation):
db.collection.aggregate([
{
"$match": {
"loc.0": { "$gte": -75 },
"loc.1": { "$lte": 70 }
}
},
{
"$group": {
"_id": 0,
"average": {
"$avg": "$pop"
}
}
}
])
With the example above, this outputs to console:
/* 1 */
{
"result" : [
{
"_id" : 0,
"average" : 12604
}
],
"ok" : 1
}
With Java, this can be implemented as follows:
DBObject match = new BasicDBObject();
match.put("loc.0", new BasicDBObject("$gte", -75));
match.put("loc.1", new BasicDBObject("$lte", 70));
DBObject groupFields = new BasicDBObject( "_id", 0);
groupFields.put("average", new BasicDBObject( "$avg", "$pop"));
DBObject group = new BasicDBObject("$group", groupFields);
AggregationOutput output = collection.aggregate( match, group );