Spring Data Mongo Query to query with multiple fields and return in one call - mongodb

Firstly, the document schema am querying on, is as follows:
{x:10, y:"temp", z:20}
There are multiple other documents in the collection with the same schema as above.
Now, I have a list where each element contains, pair of values belonging to keys x and y. This can be pictured as:
[{10,"temp"}, {20,"temp1"}, .....]
keys -> x y x y
Now, am aware, that if I process the array in a loop and take each pair, I can construct a query like:
query.addCriteria(Criteria.where("x").is(10).and("y").is("temp"))
This will return the document if it matches the AND criteria. I can query with all the pairs in the list in such a manner. But this approach will involve a high number of calls to the data base since for each pair in the list, there is a database call.
To avoid this, Is there any way I can query for all the documents that match this AND criteria for each element in the list, in a single call, using spring data MongoDb Api? Framed differently, I want to avoid looping through the array and making multiple calls, if possible.

You could use Criteria.orOperator to return each Document that match at least one Criteria of your list.
Build your list of Criteria looping over your list
List<Criteria> criteriaList = new ArrayList<>();
for (item : yourList) {
criteriaList.add(Criteria.where("x").is(item.x).and("y").is(item.y));
}
Build your query using orOperator:
Query.query(new Criteria.orOperator(criteriaList.toArray(new Criteria[criteriaList.size()])));

Related

MongoDB with Spring Boot mapping order to List

I am currently using "spring-boot-starter-data-mongodb" for persisting documents to a collection in mongodb.
The document contains a List with nested objects like:
{
foo:bar,
foos: [
{
foo1: bar1,
foo2: bar2
},
{
foo1: bar4,
foo2: bar3
}
]
}
The mapping of these documents consist the following:
private String foo;
private List<Foo> foos;
Foo:
private String foo1;
private String foo2;
The business logic is heavily depending on the order of the foos (the List elements).
The real questions are:
Are inserting a document preserves the order of the elements, so that the first item in the list will be the first in the JSON and so on?
Are querying preserves the order of the elements, so if an element is the N-th member of the document in the DB, will it be the N-th element in the mapped object as well?
Currently it seems to be true but I need to make sure it is guaranteed.
Yes, AFAIK the sort is guaranteed because MongoDB stores the document as it is. The document is stored and there is no reason to modify values from the array when read it.
Also, there are a couple questions here in StackOverflow like:
Do arrays stored in MongoDB keep their order?
Is the order of elements inside a MongoDB array guaranteed to be consistent?
Are arrays in MongoDB documents always kept in order?
So as seen before, assuming MongoDB preserves the order of elements within an array, when querying the collection in Spring Data MongoDB the returned documents will be mapped to the corresponding objects.
So the order of elements in the List of your object will be the same as the order of the elements in the array into MongoDB document.

Query for a list contained in another list With Spring Data MongoDb Criterias

I'm trying to search a list contained another list with Mongodb.
{_id:1,list:[1,2,3,4]}
{_id:2,list:[1]}
{_id:3,list:[1,3,4,6]}
I' going to search with list of strings. lets say list L =[1,2,3,4,5]
for example with the given list L = [1,2,3,4,5] I want document with _id 1 and 2 to be returned. 3 must not be returned since 6 isn't in L.
I found two solutions
one
two
Since I want to use Spring Data MongoDb Criterias, I tried to write the above solution but the code seems to be not working and it returns all the documents. Any idea how to write this mongo query with spring data mongo Criterias
You can use:
List<Integer> l = List.of(1,2,3,4,5);
Query query = new Query();
query.addCriteria(Criteria.where("list").not().elemMatch(new Criteria().nin(l)));

Mongo find unique results

What's the easiest way to get all the documents from a collection that are unique based on a single field.
I know I can use db.collections.distrinct to get an array of all the distinct values of a field, but I want to get the first (or really any one) document for every distinct value of one field.
e.g. if the database contained:
{number:1, data:'Test 1'}
{number:1, data:'This is something else'}
{number:2, data:'I'm bad at examples'}
{number:3, data:'I guess there\'s room for one more'}
it would return (based on number being unique:
{number:1, data:'Test 1'}
{number:2, data:'I'm bad at examples'}
{number:3, data:'I guess there\'s room for one more'}
Edit: I should add that the server is running Mongo 2.0.8 so no aggregation and there's more results than group will support.
Update to 2.4 and use aggregation :)
When you really need to stick to the old version of MongoDB due to too much red tape involved, you could use MapReduce.
In MapReduce, the map function transforms each document of the collection into a new document and a distinctive key. The reduce function is used to merge documents with the same distincitve key into one.
Your map function would emit your documents as-is and with the number-field as unique key. It would look like this:
var mapFunction = function(document) {
emit(document.number, document);
}
Your reduce-function receives arrays of documents with the same key, and is supposed to somehow turn them into one document. In this case it would just discard all but the first document with the same key:
var reduceFunction = function(key, documents) {
return documents[0];
}
Unfortunately, MapReduce has some problems. It can't use indexes, so at least two javascript functions are executed for every single document in the collections (it can be limited by pre-excluding some documents with the query-argument to the mapReduce command). When you have a large collection, this can take a while. You also can't fully control how the docments created by MapReduce are formed. They always have two fields, _id with the key and value with the document you returned for the key.
MapReduce is also hard to debug an troubleshoot.
tl;dr: Update to 2.4

MongoDB $in not only one result in case of repeated elements

I need to get the users whose ids are contained in an array. For this i'm using the $in operator, however being this inside an aggregate operation, i'd like to get back a specific user all the time it's id is present in the array, not just one. For example:
The ids array is A=[a,b,c,b] and U(x) is user with id x
with users.find({_id:{$in:A}}) i get these users as result: U(a),U(b),U(c)
instead i'd like to get back the result: U(a),U(b),U(c),U(b)
so get the user back every time it's id appears.
I understand that $in is working as expected but does anyone have an idea on how can i achieve this?
Thanks
This isn't possible using a MongoDB query.
MongoDB's query engine iterates over the documents in a collection (or over an index if there's a useful one) and returns to you any documents that match your query, in the order it finds them. Whether b appears once, twice, or a hundred times in your query makes no difference: the document with _id of b matches the query and is returned once, when MongoDB finds it.
You can do a post-processing step in your programming language to repeat documents as many times as you want.

accessing fieldnames as metadata in mongodb

I have a number of different documents in a mongo collection.
The attrs are all numeric values. I don't know apriori what the fieldnames are (I do but they can vary from doc to doc).
I want to write a program that
a) gets all the unique fieldnames in a collection
b) finds the max and min value of each field in the collection
and then reports it in a tabular form with rows "fieldname, maxvalue, minvalue" or in JSON that is equivalent. I am using pymongo but I don't have to, ruby or js or even java driver is fine.
How do I get programmatic access to the list of unique fieldnames in a collection? That's
the major question. I can manage the rest.
Either you main the list of used key inside your application as part of your application logic in some document inside the same collection or a meta-collection yourself or you have to iterate over all documents to figure out the list of keys...there is nothing in MongoDB helping you here since MongoDB is schemaless.