How to retrieve data from an array from a mongodb document - java

I have a question about how to retrieve data from a mongodb and how to store it in my Java code. I select all the documents (there are only 5) from my mongodb and then store its content in my Java application.
So my code is as follows:
public class MongoReader {
private Invoice invoice;
public void mongoReader () {
MongoClientURI uri = new MongoClientURI("my-url");
try (MongoClient mongoClient = new MongoClient(uri)) {
MongoDatabase database = mongoClient.getDatabase("BiFiBEP02");
MongoCollection<Document> mongoCollection = database.getCollection("bifi");
FindIterable<Document> documents = mongoCollection.find();
for (Document document : documents){
invoice.setCustomerId(document.getInteger("customerId"));
invoice.setDate(document.getDate("date"));
invoice.setInvoiceId(document.getInteger("invoiceId"));
invoice.setInvoiceLines(document.getList("invoiceLines", ArrayList<InvoiceLine>));
invoice.setNote(document.getString("note"));
invoice.setPersonId(document.getInteger("personId"));
}
}
catch (MongoException mongoException) {
mongoException.printStackTrace();
}
}
}
The document.getList() doesn't seem to be satisfied with my input.
An example of the the mongo document:
"customerId" : 2,
"date" : ISODate("2018-05-16T10:23:40.049Z"),
"invoiceId" : 1,
"invoiceLines" : [
{
"btwCode" : "hoog",
"productId" : 1,
"productName" : "BiFi worstjes voordeelstrip",
"quantity" : 20,
"totalPrice" : 30,
"unit" : "kg"
},
{
"btwCode" : "hoog",
"productId" : 2,
"productName" : "BiFi worstjes kip",
"quantity" : 20,
"totalPrice" : 30,
"unit" : "kg"
},
{
"btwCode" : "laag",
"productId" : 3,
"productName" : "BiFi worstjes extra scherp",
"quantity" : 30,
"totalPrice" : 100.22,
"unit" : "kg"
},
{
"btwCode" : "geen",
"productId" : 1,
"productName" : "BiFi worstjes promotiestand",
"quantity" : -1,
"totalPrice" : 30.32,
"unit" : "kg"
}
],
"note" : "This invoice is very important!",
"personId" : 2
So my question here is: I have to put the invoiceLines in arraylist in my Java object, but I cannot get the array items out of the mongoDb. How do I do this?

Related

Grouping by property using Mongo repository

I use the Java Spring MongoDB repository in my project.
I have this collection in MongoDB called Info:
{ "_id" : 1, "hosting" : "hostgator.com", count:7 }
{ "_id" : 2, "hosting" : "aws.amazon.com", count:7}
{ "_id" : 3, "hosting" : "aws.amazon.com", count:3}
{ "_id" : 4, "hosting" : "hostgator.com", count:5 }
{ "_id" : 5, "hosting" : "aws.amazon.com", count:1 }
{ "_id" : 6, "hosting" : "cloud.google.com", count:1 }
{ "_id" : 7, "hosting" : "aws.amazon.com", count:5 }
{ "_id" : 8, "hosting" : "hostgator.com", count:2 }
{ "_id" : 9, "hosting" : "cloud.google.com", count:3 }
{ "_id" : 10,"hosting" : "godaddy.com", count:7 }
...
{ "_id" : 100, "hosting" : "godaddy.com", count:5 }
Here is DTO definition:
public class Info{
public int _id;
public String hosting;
public int count;
}
I need to write a query and to get from the database all values of count property and remove the duplications. For example, the result that I expect according to the collection above is:
List<int> counts = [1,2,3,5,7];
For this purpose I use the aggregation group method and MongoTemplate:
GroupOperation groupOperation = Aggregation.group("count");
Aggregation aggregation = Aggregation.newAggregation(groupOperation);
var result = template.aggregate(aggregation, Info.class, Info[].class);
System.out.println(result.getMappedResults());
But the result that I get is an empty array - [].
Why I don't get the expected result?

Get count of unique ObjectId from array MongoDB

I'm new to working with MongoDb and do not know a lot of things.
I need to write an aggregation request.
Here is the JSON document structure.
{
"_id" : ObjectId("5a72f7a75ef7d430e8c462d2"),
"crawler_id" : ObjectId("5a71cbb746e0fb0007adc6c2"),
"skill" : "stack",
"created_date" : ISODate("2018-02-01T13:19:03.522+0000"),
"modified_date" : ISODate("2018-02-01T13:22:23.078+0000"),
"connects" : [
{
"subskill" : "we’re",
"weight" : NumberInt(1),
"parser_id" : [
ObjectId("5a71d88d5ef7d41964fbec11")
]
},
{
"subskill" : "b1",
"weight" : NumberInt(2),
"parser_id" : [
ObjectId("5a71d88d5ef7d41964fbec11"),
ObjectId("5a71d88d5ef7d41964fbec1b")
]
},
{
"subskill" : "making",
"weight" : NumberInt(2),
"parser_id" : [
ObjectId("5a71d88d5ef7d41964fbec1b"),
ObjectId("5a71d88d5ef7d41964fbec1c")
]
},
{
"subskill" : "delivery",
"weight" : NumberInt(2),
"parser_id" : [
ObjectId("5a71d88d5ef7d41964fbec1c"),
ObjectId("5a71d88d5ef7d41964fbec1e")
]
}
]
}
I need the result return the name of skill and the number of unique parser_id.
In this case, the result should be:
[
{
"skill": "stack",
"quantity": 4
}
]
where "stack" - skill name,
and "quantity" - count of unique parser_id.
ObjectId("5a71d88d5ef7d41964fbec11")
ObjectId("5a71d88d5ef7d41964fbec1b")
ObjectId("5a71d88d5ef7d41964fbec1c")
ObjectId("5a71d88d5ef7d41964fbec1e")
Can some one help me with this request ???
Given the document supplied in your question, this command ...
db.collection.aggregate([
{ $unwind: "$connects" },
// count all occurrences
{ "$group": { "_id": {skill: "$skill", parser_id: "$connects.parser_id"}, "count": { "$sum": 1 } }},
// sum all occurrences and count distinct
{ "$group": { "_id": "$_id.skill", "quantity": { "$sum": 1 } }},
// (optional) rename the '_id' attribute to 'skill'
{ $project: { 'skill': '$_id', 'quantity': 1, _id: 0 } }
])
... will return:
{
"quantity" : 4,
"skill" : "stack"
}
The above command groups by skill and connects.parser_id and then gets a distinct count of those groups.
Your command includes the java tag so I suspect you are looking to execute the same command using the MongoDB Java driver. The code below (using MongoDB Java driver v3.x) will return the same result:
MongoClient mongoClient = ...;
MongoCollection<Document> collection = mongoClient.getDatabase("...").getCollection("...");
List<Document> documents = collection.aggregate(Arrays.asList(
Aggregates.unwind("$connects"),
new Document("$group", new Document("_id", new Document("skill", "$skill").append("parser_id", "$connects.parser_id"))
.append("count", new Document("$sum", 1))),
new Document("$group", new Document("_id", "$_id.skill").append("quantity", new Document("$sum", 1))),
new Document("$project", new Document("skill", "$_id").append("quantity", 1).append("_id", 0))
)).into(new ArrayList<>());
for (Document document : documents) {
logger.info("{}", document.toJson());
}
Note: this code deliberately uses the form new Document(<pipeline aggregator>, ...) instead of the Aggregators utilities to make it easier to see the translation between the shell command and its Java equivalent.
try $project with $reduce
$setUnion is used to keep only the distinct ids and finally $size used to get the distinct array count
db.col.aggregate(
[
{$project : {
_id : 0,
skill : 1,
quantity : {$size :{$reduce : {input : "$connects.parser_id", initialValue : [] , in : {$setUnion : ["$$value", "$$this"]}}}}
}
}
]
).pretty()
result
{ "skill" : "stack", "quantity" : 4 }

MongoDB $graphlookup in Java Spring Data

I'm looking for a way to implement graphlookup using Java in a Resful Web API. I'm trying to implement the hierarchy like on the MongoDB (https://docs.mongodb.com/v3.4/reference/operator/aggregation/graphLookup/)
{ "_id" : 1, "name" : "Dev" }
{ "_id" : 2, "name" : "Eliot", "reportsTo" : "Dev" }
{ "_id" : 3, "name" : "Ron", "reportsTo" : "Eliot" }
{ "_id" : 4, "name" : "Andrew", "reportsTo" : "Eliot" }
{ "_id" : 5, "name" : "Asya", "reportsTo" : "Ron" }
{ "_id" : 6, "name" : "Dan", "reportsTo" : "Andrew" }
This is the employee collection, what I want is to be able to create this structure stored in MongoDB
{
"_id" : 1,
"name" : "Dev",
"reportingHierarchy" : [ ]
}
{
"_id" : 2,
"name" : "Eliot",
"reportsTo" : "Dev",
"reportingHierarchy" : [
{ "_id" : 1, "name" : "Dev" }
]
}
{
"_id" : 3,
"name" : "Ron",
"reportsTo" : "Eliot",
"reportingHierarchy" : [
{ "_id" : 1, "name" : "Dev" },
{ "_id" : 2, "name" : "Eliot", "reportsTo" : "Dev" }
]
}
I've seen examples like this for aggregation, but nothing on graphlookup
Aggregation agg = newAggregation(
match(Criteria.where("pageId").is("2210")),
unwind("postIds"),
group("_id").sum("1").as("sum")
//project("$sum").and("pageId").previousOperation()
);
Is there a way to get graphlookup into a format like this? Where instead of using match, unwind, group, I can use GraphLookupOperation and then something like get map result.
AggregationOperation aggregationOperation = new AggregationOperation() {
#Override public DBObject toDBObject(AggregationOperationContext aggregationOperationContext) {
DBObject graphLookup = new BasicDBObject(
"from", "individual").append(
"startWith", "$reportsTo").append(
"connectFromField", "reportsTo").append(
"connectToField", "firstName").append(
"maxDepth", 2).append(
"as", "reportingHierarchy");
return new BasicDBObject("$graphLookup", graphLookup);
This code allows for a workaround since i'm using an older version, I think 1.10.0 spring mongo. Now I have the issues of the "reportingHierarchy" not looking like I want it to. It's not giving me a name. Just reportsTo and reportingHierarchy that is also including _class which I don't want.

MongoDB Java Driver updates unmatched sub-document

I'm using mongo-java-driver:3.3.0 and trying to update one value of my sub-document using $inc operator and findOneAndUpdate, but only under certain conditions (id comparison and greaterThan filter).
Following is a snippet to reproduce the problem:
MongoCollection<Document> coll = db.getCollection("update_increase");
Document docBefore = new Document()
.append("subdocs", Arrays.asList(
new Document("id", "AAA").append("count", 10),
new Document("id", "BBB").append("count", 20)
));
coll.insertOne(docBefore);
Document filter = new Document()
.append("subdocs.id", "BBB")
.append("subdocs.count", new Document("$gt", 7));
Document update = new Document()
.append("$inc", new Document("subdocs.$.count", -7));
Document docAfter = coll.findOneAndUpdate(
filter,
update,
new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER));
docBefore:
{ "_id" : { "$oid" : "5819c85977a8cb12f8d706c9" },
"subdocs" : [
{ "id" : "AAA", "count" : 10 },
{ "id" : "BBB", "count" : 20 }
]
}
docAfter:
{ "_id" : { "$oid" : "5819c85977a8cb12f8d706c9" },
"subdocs" : [
{ "id" : "AAA", "count" : 3 },
{ "id" : "BBB", "count" : 20 }
]
}
What I expected is count:13 on the second subdoc (id:"BBB"), but I got an update on the first one (count:3).
This works fine if I remove greaterThan condition line (.. new Document("$gt", 5) ..):
{ "_id" : { "$oid" : "5819c92577a8cb13404cfc91" },
"subdocs" : [
{ "id" : "AAA", "count" : 10 },
{ "id" : "BBB", "count" : 13 }
]
}
What I'm doing wrong?
Thanks!
Here is the java equlivant for $elemMatch.
Document filter = new Document("subdocs", new Document().append("$elemMatch", new Document().append("id", "BBB").append("count", new Document("$gt", 7))));

Mongo driver updateMany not updating all documents

Using Mongo Java Driver version 3.2.1 against MongoDB 3.0.12.
Calling MongoCollection.updateMany(Bson filter, Bson update) returns a result showing all expected documents were modified, however only a portion of the documents were actually updated.
I've tried with multiple write concerns: JOURNALED, ACKNOWLEDGED, etc
Any ideas?
Here is the profile result:
{ "op" : "update", "ns" : "dev.timeSheet", "query" : { "lineItems.task" : ObjectId("53233e85e4b07f573f1d4466") }, "updateobj" : { "$set" : { "lineItems.$.task" : ObjectId("53233e85e4b07f573f1d446d") } }, "nscanned" : 0, "nscannedObjects" : 6733, "nMatched" : 248, "nModified" : 248, "fastmod" : true, "keyUpdates" : 0, "writeConflicts" : 0, "numYield" : 52, "locks" : { "Global" : { "acquireCount" : { "r" : NumberLong(53), "w" : NumberLong(53) } }, "MMAPV1Journal" : { "acquireCount" : { "w" : NumberLong(301) } }, "Database" : { "acquireCount" : { "w" : NumberLong(53) } }, "Collection" : { "acquireCount" : { "W" : NumberLong(53) } } }, "millis" : 50, "execStats" : { }, "ts" : ISODate("2016-08-25T18:17:16.025Z"), "client" : "127.0.0.1", "allUsers" : [ ], "user" : "" }
Update: Also occurs in MongoDB 3.2.9
Direct access calls:
db.timeSheet.find({'lineItems.task': ObjectId("53233e85e4b07f573f1d4466")}).count()
126
db.timeSheet.updateMany({'lineItems.task': ObjectId("53233e85e4b07f573f1d4466")}, {'$set': {'lineItems.$.task': ObjectId("53233e85e4b07f573f1d446d")}})
{ "acknowledged" : true, "matchedCount" : 126, "modifiedCount" : 126 }
db.timeSheet.find({'lineItems.task': ObjectId("53233e85e4b07f573f1d4466")}).count()
90
This isn't working the way I expected because it is only updating the first lineItem it finds for each time sheet.
https://docs.mongodb.com/manual/reference/operator/update/positional/#up.S
Remember that the positional $ operator acts as a placeholder for the first match of the update query document.
No feature exists currently to update all items in the embedded array.
https://jira.mongodb.org/browse/SERVER-1243

Categories