Some magic in find - regex

In Mongo FIND( regexp ), the number of found records is different from Meteor.
mongodb side:
> db.products.find({name:/clp/ig}).count()
4
crome js console:
> products.find({name:/clp/ig}).count()
2
Data are very simple:
{ "_id" : ObjectId("514d39f087696bb4cc3b549d"), "code" : "P615", "name" : "PENNASOL WERKZEUGMASCHINENGETRIEBEOEL CLP 68" }
{ "_id" : ObjectId("514d39f087696bb4cc3b549e"), "code" : "P616", "name" : "PENNASOL WERKZEUGMASCHINENGETRIEBEOEL CLP 100" }
{ "_id" : ObjectId("514d39f087696bb4cc3b549f"), "code" : "P617", "name" : "PENNASOL WERKZEUGMASCHINENGETRIEBEOEL CLP 150" }
{ "_id" : ObjectId("514d39f087696bb4cc3b54a0"), "code" : "P618", "name" : "PENNASOL WERKZEUGMASCHINENGETRIEBEOEL CLP 220" }
Collection
var products = new Meteor.Collection('products');
Meteor.publish( 'products', function(){
products.find();
});
Could be a bug? And where?
ps: checked on different computers. same magic.

The data may not yet be on the client when you make the call. Do you use it anywhere? The data is only fetched when it's used, so when you do the find on the client, you get result with what's already there, and the other items just start their way through the net.
To test if this is the case:
Do the same find on the server (in Meteor.startup for example) and log the results.
On the client, do Products.find({}).fetch();. Wait some time, then do your query.

All data is too old(may be year).
products.find({name:/clp/ig}).fetch();
answer is:
P615 PENNASOL WERKZEUGMASCHINENGETRIEBEOEL CLP 68
P617 PENNASOL WERKZEUGMASCHINENGETRIEBEOEL CLP 150
other
products.find({name:/clp 220/ig}).fetch();
answer is
P618 PENNASOL WERKZEUGMASCHINENGETRIEBEOEL CLP 220
It's real magic.

Related

Spring data mongo query with regex within an array

I have a collection with structure somewhat like this :
{
"organization" : "Org1",
"active" : true,
"fields" : [
{
"key" : "key1",
"value" : "table"
},
{
"key" : "key2",
"value" : "Harrison"
}
]
}
I need to find all documents with organization : "Org1", active : true, and regex match the 'value' in fields.
In mongo shell, it works perfectly. I tried the query:
db.collection.find({"organization" : "Org1", "active" : true, "fields" : {$elemMatch : {"key" : "key2","value" : {$regex : /iso/i}}}}).pretty()
But when I tried to convert it to a Java code with Spring, it gives wrong results.
1. This one will give documents even if it didn't match the pattern:
#Query("{'organization' : ?0, 'active' : true, 'fields' : {$elemMatch : {'key' : ?1, 'value' : {$regex : ?2}}}}")
List<ObjectCollection> findFieldDataByRegexMatch(String org, String key, String pattern);
This one doesn't give any documents even though it should.
MongoTemplate MONGO_TEMPLATE = null;
try {
MONGO_TEMPLATE = multipleMongoConfig.secondaryMongoTemplate();
} catch (Exception e) {
e.printStackTrace();
}
List<Criteria> criteriaListAnd = new ArrayList<Criteria>();
Criteria criteria = new Criteria();
String pattern = "/iso/i";
criteriaListAnd.add(Criteria.where("organization").is("Org1"));
criteriaListAnd.add(Criteria.where("active").is(true));
criteriaListAnd.add(Criteria.where("fields").elemMatch(Criteria.where("key").is(key).and("value").regex(pattern)));
criteria.andOperator(criteriaListAnd.toArray(new Criteria[criteriaListAnd.size()]));
Query query = new Query();
query.addCriteria(criteria);
List<ObjectCollection> objects = MONGO_TEMPLATE.find(query, ObjectCollection.class);
What am I missing here and how should I form my query?
You are making a very small mistake, in the pattern you are passing / which is the mistake, it took me half an hour to identify it, finally, I got it after enabling the debug log of spring boot.
For the first query, it should be called as below:
springDataRepository.findFieldDataByRegexMatch("Org1", "key2", "iso")
And the query should be modified in the Repository as to hanlde the case sensetivity:
#Query("{'organization' : ?0, 'active' : true, 'fields' : {$elemMatch : {'key' : ?1, 'value' : {$regex : ?2, $options: 'i'}}}}")
List<Springdata> findFieldDataByRegexMatch(String org, String key, String pattern);
The same issue in your second query also, just change String pattern = "/iso/i"; to String pattern = "iso" or String pattern = "iso.*" ;
Both will start working, For details please check the my GitHub repo https://github.com/krishnaiitd/learningJava/blob/master/spring-boot-sample-data-mongodb/src/main/java/sample/data/mongo/main/Application.java#L60
I hope this will resolve your problem.

Group documents using substring of a field

I am working with MongoDB and I am enjoying a lot!
There is one query I am having problems to work with:
I have this set of data that represents an hierarchy (a tree, where 1 is the root, 1.1 and 1.2 are children of 1, and so on)
db.test.insert({id:1, hierarchy:"1"})
db.test.insert({id:2, hierarchy:"1.1"})
db.test.insert({id:3, hierarchy:"1.2"})
db.test.insert({id:4, hierarchy:"1.1.1"})
db.test.insert({id:5, hierarchy:"1.1.2"})
db.test.insert({id:6, hierarchy:"1.2.1"})
db.test.insert({id:7, hierarchy:"1.2.2"})
db.test.insert({id:8, hierarchy:"1.2.3"})
So if I make a query:
> db.test.find()
{ "_id" : ObjectId("546a6095cafd2fa3ff8e4760"), "id" : 1, "hierarchy" : "1" }
{ "_id" : ObjectId("546a6095cafd2fa3ff8e4761"), "id" : 2, "hierarchy" : "1.1" }
{ "_id" : ObjectId("546a6095cafd2fa3ff8e4762"), "id" : 3, "hierarchy" : "1.2" }
{ "_id" : ObjectId("546a6095cafd2fa3ff8e4763"), "id" : 4, "hierarchy" : "1.1.1" }
{ "_id" : ObjectId("546a6095cafd2fa3ff8e4764"), "id" : 5, "hierarchy" : "1.1.2" }
{ "_id" : ObjectId("546a6095cafd2fa3ff8e4765"), "id" : 6, "hierarchy" : "1.2.1" }
{ "_id" : ObjectId("546a6095cafd2fa3ff8e4766"), "id" : 7, "hierarchy" : "1.2.2" }
{ "_id" : ObjectId("546a6095cafd2fa3ff8e4767"), "id" : 8, "hierarchy" : "1.2.3" }
the document with id 1 represents the CEO and I would like to gather information about the teams under the VPs (1.1 and 1.2).
I would like to have an output like this
{
id: null,
teams:
[
{
manager: 2,
hierarchy: "1.1",
subordinates: 2
},
{
manager: 3,
hierarchy: "1.2",
subordinates: 3
}
]
}
I am having problems to aggregate the documents in the right "slot".
I tried to use a regex to aggregate using the substring, and project before grouping and create a new field which would be "manager_hierarchy", so I could group using this field. But with none of these approaches I had any kind of success, so I am stuck now.
Is there anyway I could accomplish this task?
EDIT: sorry, I forgot to make one thing explicit:
This query is to get information about subordinate teams of an employee. I've used an example as the CEO, but if I was the employee 1.2.3 in the hierarchy, I would like to see the teams 1.2.3.1, 1.2.3.2, ..., 1.2.3.xx
There is also the possibility (rare, but possible) that someone has more than 9 subordinates, so making a "hardcoded" substring would not work, since
$substr:["$hierarchy",0,3]}
would work for 1.2 but not for 1.10
and
$substr:["$hierarchy",0,4]}
would work for 1.10, but not for 1.2
You can get your results using the below aggregate pipeline operations.
Sort the rows based on their hierarchy, so that the manager
comes on top.
Group together records that start with similar ancestors.(i.e 1.1
or 1.2,...). The manager record will be on top for each group
due to the above sort operation.
Take the count of each group, so the number of subordinates
will be count-1(the manager record).
Again group the records to get a single array.
The code:
db.test.aggregate([
{$match:{"id":{$gt:1}}},
{$sort:{"hierarchy":1}},
{$group:{"_id":{"grp":{$substr:["$hierarchy",0,3]}},
"manHeir":{$first:"$hierarchy"},
"count":{$sum:1},"manager":{$first:"$id"}}},
{$project:{"manager":1,
"hierarchy":"$manHeir",
"subordinates":{$subtract:["$count",1]},"_id":0}},
{$group:{"_id":null,"teams":{$push:"$$ROOT"}}},
{$project:{"_id":0,"teams":1}}
])

Match with substring in mongodb aggregation

In my mongodb collection, I have a time_stamp="2013-06-30 23:58:37 928".
I need to use "$match" with only the date, like time_stamp="2013-06-30". So how can I get the substring like that ?
Previously I've tried with $substr, but it shows an error "errmsg" : "exception: invalid operator: $substr"
I think you are trying to make query using aggregation framework since you tried $match & $substr operators. I have created a simple example to show how you can use $substr to achive result you wanted on aggregation framework.
I have inserted following data into the MongoDB.
{ "_id" : ObjectId("528b343881d4fe2cfe0b1b25"), "time_stamp" : "2013-06-30 23:58:37 928" }
{ "_id" : ObjectId("528b343b81d4fe2cfe0b1b26"), "time_stamp" : "2013-06-30 23:58:37 928" }
{ "_id" : ObjectId("528b344c81d4fe2cfe0b1b27"), "time_stamp" : "2013-06-30 12:58:37 928" }
{ "_id" : ObjectId("528b344f81d4fe2cfe0b1b28"), "time_stamp" : "2013-06-30 12:58:23 928" }
{ "_id" : ObjectId("528b345381d4fe2cfe0b1b29"), "time_stamp" : "2013-06-31 12:58:23 928" }
{ "_id" : ObjectId("528b345981d4fe2cfe0b1b2a"), "time_stamp" : "2013-07-31 12:58:23 933" }
I wrote following code to group by date by using $substr operator.
db.myObject.aggregate(
{$project : {new_time_stamp : {$substr : ["$time_stamp",0, 10]}}},
{$group:{_id:"$new_time_stamp", "count": {$sum:1}}}
);
$substr operation failed because you there is no such operation for find. You can only use it in aggregation framework. You mentioned that you have a timestamp. In such a case you need to query by time interval.
{time_stamp: {
$gte: ISODate("2013-06-30T00:00:00Z"),
$lt: ISODate("2013-06-31T00:00:00Z")
}}
I hope that this month has 31 days. If it is a string ( which is really bad because dates should be stored as dates) you have to use a regex.

JasperReports MongoDB List Data

I am fairly new to JasperReports and am having a challenge getting list data to show up correctly from MongoDB.
I was working off of an article, but cannot seem to get it to work.
I have the following collection in MongoDB:
{ "_id" : ObjectId("51e24462945f8796ea8e731d"), "id" : "1001", "cust" : "abc", "
lines" : [ { "line number" : "line1", "product" : "ProdA" },
{ "line number" : "line2", "product" : "ProdB" } ] }
{ "_id" : ObjectId("51e246fb945f8796ea8e731e"), "id" : "1002", "cust" : "abc", "
lines" : [ { "line number" : "line1", "product" : "ProdA" },
{ "line number" : "line2", "product" : "ProdB" } ] }
"lines" is a collection.
In iReport, it shows up as a list, which is good. However, when I do as the article suggests and change the sub datasource to new net.sf.jasperreports.engine.data.JRMapCollectionDataSource($F{lines}), I still get the List as a string, which just shows up as
[[line number : line1, product: ProdA],[line number : line2, product: ProdB]]
Shouldn't using this JRMapCollectionDataSource parse this out for me already? If not, how do I handle this?
Have you tried to access the list data by using field names "lines.line number" and "lines.product"? That might do the trick.
I figured this out. You have to create an empty data set and from there map the fields to the ${lines} array. For anyone that finds themselves in the same predicament as myself, I highly recommend reading the example JRXML file the author put into the article (something I didn't notice was there at first).
Thanks

combining regex and embedded objects in mongodb queries

I am trying to combine regex and embedded object queries and failing miserably. I am either hitting a limitation of mongodb or just getting something slightly wrong maybe someone out ther has encountered this. The documentation certainly does'nt cover this case.
data being queried:
{
"_id" : ObjectId("4f94fe633004c1ef4d892314"),
"productname" : "lightbulb",
"availability" : [
{
"country" : "USA",
"storeCode" : "abc-1234"
},
{
"country" : "USA",
"storeCode" : "xzy-6784"
},
{
"country" : "USA",
"storeCode" : "abc-3454"
},
{
"country" : "CANADA",
"storeCode" : "abc-6845"
}
]
}
assume the collection contains only one record
This query returns 1:
db.testCol.find({"availability":{"country" : "USA","storeCode":"xzy-6784"}}).count();
This query returns 1:
db.testCol.find({"availability.storeCode":/.*/}).count();
But, this query returns 0:
db.testCol.find({"availability":{"country" : "USA","storeCode":/.*/}}).count();
Does anyone understand why? Is this a bug?
thanks
You are referencing the embedded storecode incorrectly - you are referencing it as an embedded object when in fact what you have is an array of objects. Compare these results:
db.testCol.find({"availability.0.storeCode":/x/});
db.testCol.find({"availability.0.storeCode":/a/});
Using your sample doc above, the first one will not return, because the first storeCode does not have an x in it ("abc-1234"), the second will return the document. That's fine for the case where you are looking at a single element of the array and pass in the position. In order to search all of the objcts in the array, you want $elemMatch
As an example, I added this second example doc:
{
"_id" : ObjectId("4f94fe633004c1ef4d892315"),
"productname" : "hammer",
"availability" : [
{
"country" : "USA",
"storeCode" : "abc-1234"
},
]
}
Now, have a look at the results of these queries:
PRIMARY> db.testCol.find({"availability" : {$elemMatch : {"storeCode":/a/}}}).count();
2
PRIMARY> db.testCol.find({"availability" : {$elemMatch : {"storeCode":/x/}}}).count();
1