query array of embedded documents in spring data mongodb - spring-data-mongodb

I have simple question:
How do I express this query
db.inventory.find( { "instock": { warehouse: "A", qty: 5 } } )
Query for a Document Nested in an Array
in spring data mongoDB, preferably using QueryDSL but other ways are welcome, too.
All my queries so far match fields on any embedded document in the array but I need to match both on the same.

Using Spring Data repository, you could use :
1 - #Query annotation
#Query("{ 'instock': { 'warehouse': ?0, 'qty': ?1 } }")
List<YourClass> findByInstock(String warehouse, int qty);
2 - Custom repository method implementation
List<YourClass> findByInstock(String warehouse, int qty) {
return mongoTemplate.find(Query.query(Criteria.where("instock").elemMatch(Criteria.where("warehouse").is(warehouse).and("qty").is(qty)));
You can find more material here on how to implement this method.
}

Related

Spring data mongodb in clause with case insensitive

Is it possible to use IN clause in spring data mongodb with case insensitivity?
For example my Customer model have a field email and I want to get the list of customers from the list of emails I have.
Normally in JPA, I can get the list of customers from emails using findAllByEmailIn(List<String> emails)
I am thinking of setting the emails to lowercase, but this still is not as safe as case insensitive.
Something like:
findAllByEmailIn(emails.stream().map(String::toLowerCase).collect(Collectors.toList()))
OR
Query query = new Query();
query.addCriteria(where("email").in(emails.stream()
.map(String::toLowerCase).collect(Collectors.toList())));
return m_mongoTemplate.find(query, Customer.class);
Is there a way to use IN clause with case insensitivity? Either by JPA findAllBy magic, or by query criterias?
You can try using RegEx
{ email: { $in: [ /^test1#Gmail.Com/i, /^TEST2#gmail.COM/i ] } }

How to print the count of array elements along with another variable in MongoDB

I have a data collection which contains records in the following format.
{
"_id": 22,
"title": "Hibernate in Action",
"isbn": "193239415X",
"pageCount": 400,
"publishedDate": ISODate("2004-08-01T07:00:00Z"),
"thumbnailUrl": "https://s3.amazonaws.com/AKIAJC5RLADLUMVRPFDQ.book-thumb-images/bauer.jpg",
"shortDescription": "\"2005 Best Java Book!\" -- Java Developer's Journal",
"longDescription": "Hibernate practically exploded on the Java scene. Why is this open-source tool so popular Because it automates a tedious task: persisting your Java objects to a relational database. The inevitable mismatch between your object-oriented code and the relational database requires you to write code that maps one to the other. This code is often complex, tedious and costly to develop. Hibernate does the mapping for you. Not only that, Hibernate makes it easy. Positioned as a layer between your application and your database, Hibernate takes care of loading and saving of objects. Hibernate applications are cheaper, more portable, and more resilient to change. And they perform better than anything you are likely to develop yourself. Hibernate in Action carefully explains the concepts you need, then gets you going. It builds on a single example to show you how to use Hibernate in practice, how to deal with concurrency and transactions, how to efficiently retrieve objects and use caching. The authors created Hibernate and they field questions from the Hibernate community every day - they know how to make Hibernate sing. Knowledge and insight seep out of every pore of this book.",
"status": "PUBLISH",
"authors": ["Christian Bauer", "Gavin King"],
"categories": ["Java"]
}
I want to print title, and authors count where the number of authors is greater than 4.
I used the following command to extract records which has more than 4 authors.
db.books.find({authors:{$exists:true},$where:'this.authors.length>4'},{_id:0,title:1});
But unable to print the number of authors along with the title. I tried to use the following command too. But it gave only the title list.
db.books.find({authors:{$exists:true},$where:'this.authors.length>4'},{_id:0,title:1,'this.authors.length':1});
Could you please help me to print the number of authors here along with the title?
You can use aggregation framework's $project with $size to reshape your data and then $match to apply filtering condition:
db.collection.aggregate([
{
$project: {
title: 1,
authorsCount: { $size: "$authors" }
}
},
{
$match: {
authorsCount: { $gt: 4 }
}
}
])
Mongo Playground

is it possible to get all documents using criteria on two fields with a max date

I have documents in a 'merge' collection with flat structure and a huge number of 'fields' (more than 100).
Amongst those fields have 'partNumber', and 'date' which are not unique.
I am newbie in mongo, I need to retrieve all documents (and all their fields, without needing to list them explicitely in a project stage), but selecting only the records which have the latest date for a given partNumber (and this for all partNumbers).
Is that possible in mongoDB 3.2 ? What would be the query ?
Many thanks in advance.
yes it is possible, Do you want to know MongoDB query for this thing? Or Are you using any backend programming language ?
After struggling on complex aggregation queries, I found a KISS solution with some code and only 2 queries:
- 1 aggregation query to retrieve couples partNumber, most recent date
db.getCollection('merge').aggregate(
[
{ $group : { _id : "$partNumber", maxdate: { $max: "$date" } } }
]
)
Then in python, a single find query using all tuples parsed from previous step with (partNumber = partNumber1 and date = date1) or (partNumber = partNumber2 and date = date 2) or ...
Performs very fast.

indexing large array in mongoDB

according to mongoDB documentation, it's not recommended to create multikey index for large arrays, so what is the alternative option for that?
I want to notify my app users whenever one of their contacts also start using the app, so I have to upload and manage the contacts list of each user.
we are using mongoDB with replica set of master with two secondaries machines.
does mongo can handle multikey indexing for array with hundreds of values?
hundreds of contacts for hundreds thousands of users can be very hard to mange.
the multikey solution looks like that:
{
customerId: "id1",
contacts: ["aaa", "aab", "aac", .... "zzz"]
}
index: createIndex({ contacts: 1 }).
another solution is to save each contacts in it's own document and save all the app users that related to him:
{
phone: "aaa",
contacts: ["id1", "id2", "id3"]
},
{
phone: "aab",
contacts: ["id1"]
},
{
phone: "aac",
contacts: ["id1"]
},
......
{
phone: "zzz",
contacts: ["id1"]
}
index: createIndex( { phone: 1 } )
both have poor performance on writing when uploading the contacts list:
the first on calculate huge index, and the second for updating lots of documents concurrent.
Is there a better way to do it?
I'm using a replica set with two secondaries machines, does shard key could help?
Thanks
To index a field that holds an array value, MongoDB creates an index key for each element in the array. These multikey indexes support efficient queries
against array fields.
So if i were you, my data model would be like this :
{
customerId: "id1",
contacts: ["_idx", "_idy", "_idw", .... "_idz"]
}
And then create your index on the contacts. MongoDB creates by default indexes on ids. So you will have to create new documents for the non app users, just try to to add a field, like "app_user" : true/false.
For index performance, you could make it build in the background without any issues, and for replica sets, this is how it's done.
For the sharding, it won't help you, because you won't even be able to shard anything, since you have one primary node in your cluster. Sharding needs at least 2 sets of primary Mongo instances, so in your case, you could add a fourth server, then have two replica sets, of one primary and one secondary, then shard them, and tranform your system into 2 replicated shards.
Once this is achieved, it will obviously balance the loads between the 2 shards, eventhough a hundred documents isn't really much to deal with for MongoDB.
On the other hand if you're going to go for sharding, you will need more setup, for config servers if you're using Mongodb 3.4 or higher.

Querying mongoDB document based on Array element

This is one user's notes. I want to query and get only the notes of this use with "activeFlag:1". My query object code is
findAccountObj =
{ _id: objectID(req.body.accountId),
ownerId: req.body.userId,
bookId: req.body.bookId,
"notes.activeFlag": 1 };
But this query returns all the notes, including the ones with "activeFlag:0".
How do I fix this?
If you are on v2.2, use elementmatch operator. v3.2 and above allow aggregation and filter to return a subset of a document.
here is an example Retrieve only the queried element in an object array in MongoDB collection

Resources