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
Related
I have a Mongo collection that contains data on saved searches in a Vue/Laravel app, and it contains records like the following:
{
"_id" : ObjectId("6202f3357a02e8740039f343"),
"q" : null,
"name" : "FCA last 3 years",
"frequency" : "Daily",
"scope" : "FederalContractAwardModel",
"filters" : {
"condition" : "AND",
"rules" : [
{
"id" : "awardDate",
"operator" : "between_relative_backward",
"value" : [
"now-3.5y/d",
"now/d"
]
},
{
"id" : "subtypes.extentCompeted",
"operator" : "in",
"value" : [
"Full and Open Competition"
]
}
]
},
The problem is the value in the item in the rules array that has the decimal.
"value" : [
"now-3.5y/d",
"now/d"
]
in particular the decimal. Because of a UI error, the user was allowed to enter a decimal value, and so this needs to be fixed to remove the decimal like so.
"value" : [
"now-3y/d",
"now/d"
]
My problem is writing a Mongo query to identify these records (I'm a Mongo noob). What I need is to identify records in this collection that have an item in the filters.rules array with an item in the 'value` array that contains a decimal.
Piece of cake, right?
Here's as far as I've gotten.
myCollection.find({"filters.rules": })
but I'm not sure where to go from here.
UPDATE: After running the regex provided by #R2D2, I found that it also brings up records with a valid date string , e.g.
"rules" : [
{
"id" : "dueDate",
"operator" : "between",
"value" : [
"2018-09-10T19:04:00.000Z",
null
]
},
so what I need to do is filter out cases where the period has a double 0 on either side (i.e. 00.00). If I read the regex correctly, this part
[^\.]
is excluding characters, so I would want something like
[^00\.00]
but running this query
db.collection.find( {
"filters.rules.value": { $regex: /\.[^00\.00]*/ }
} )
still returns the same records, even though it works as expected in a regex tester. What am I missing?
To find all documents containing at least one value string with (.) , try:
db.collection.find( {
"filters.rules.value": { $regex: /\.[^\.]*/ }
} )
Or you can filter only the fields that need fix via aggregation as follow:
[direct: mongos]> db.tes.aggregate([ {$unwind:"$filters.rules"}, {$unwind:"$filters.rules.value"}, {$match:{ "filters.rules.value": {$regex: /\.[^\.]*/ } }} ,{$project:{_id:1,oldValue:"$filters.rules.value"}} ])
[
{ _id: ObjectId("6202f3357a02e8740039f343"), oldValue: 'now-3.5y/d' }
]
[direct: mongos]>
Later to update those values:
db.collection.update({
"filters.rules.value": "now-3.5y/d"
},
{
$set: {
"filters.rules.$[x].value.$": "now-3,5y/d-CORRECTED"
}
},
{
arrayFilters: [
{
"x.value": "now-3.5y/d"
}
]
})
playground
Is it possible to make a search to a virtual column that is composed by two columns?
Let's say I have the following MongoDB collection:
db.collection =
[
{ book : 'The Stand', author : 'Stephen King'},
{ book : 'The Dead Zone', author : 'Stephen King'},
{ book : 'Hamlet', author : 'William Shakespeare'},
{ book : 'The Tragedy of Othello', author : 'William Shakespeare'},
{ book : 'Danse Macabre', author : 'Stephen King'},
]
And I want to make a search that should be made considering both book and author columns at the same time. In particular, I will have a query string with several items separated by spaces, and I would want to return the documents whose joint book+author column contains all the query items regardless of their order.
Example:
Query: "King The"
{ book : 'The Stand', author : 'Stephen King'},
{ book : 'The Dead Zone', author : 'Stephen King'}
Query: "Tragedy Shakespeare"
{ book : 'The Tragedy of Othello', author : 'William Shakespeare'}
Query: "The"
{ book : 'The Stand', author : 'Stephen King'},
{ book : 'The Dead Zone', author : 'Stephen King'},
{ book : 'The Tragedy of Othello', author : 'William Shakespeare'},
Is this kind of search possible in MongoDB? Is there any $regex expression to make it feasible?
Thank you!
Here is an aggregation I think might help...
db.collection.aggregate([
{ $project: { book: 1, author: 1, "book_words": { $split: [ "$book", " " ] }, "author_words": { $split: [ "$author", " " ] } } },
{ $project: { book:1, author: 1, "search_words": { $concatArrays: [ "$book_words", "$author_words" ] } } },
{ $match: { "search_words": { $all: [ "The", "King" ] } } },
{ $project: { "search_words": 0} }
]).pretty()
Explanation:
This aggregation has 4 stages...
$project
$project
$match
$project
The first $project will split the string value in field "book" into an array of words called "book_words", and also split the string value in the field "author" into an array of words called "author_words"
The second $project will concatenate the two new arrays together into a single array called "search_words"
The $match stage filters out records that do not match the search criteria
the final $project stage removes the temporary array field called "search_words"
Resulting documents for this aggregation look like...
{
"_id" : ObjectId("60d6139a9148371ae7d2b343"),
"book" : "The Stand",
"author" : "Stephen King"
}
{
"_id" : ObjectId("60d6139a9148371ae7d2b344"),
"book" : "The Dead Zone",
"author" : "Stephen King"
}
Case insensitive matching
In order to provide case insensitive matching MongoDB must understand what case insensitive means. English case is different from other languages. So for this reason we must add an index with a collation that defines english as the language and a strength of 2 for the collation - meaning case insensitive for english. Once the index is created, we must refer to the collation as a option in the aggregation.
Create Index
db.collection.createIndex( { book: 1, author: 1 }, { collation: { locale: 'en', strength: 2 } } )
This is a compound index on both fields - 'book' and 'author'. Notice collation options for this index...
Aggregation using collation
Now that the index exists with a specific collation, Mongo now can calculate the case insensitive options...
db.collection.aggregate([
{ $project: { book: 1, author: 1, "book_words": { $split: [ "$book", " " ] }, "author_words": { $split: [ "$author", " " ] } } },
{ $project: { book:1, author: 1, "search_words": { $concatArrays: [ "$book_words", "$author_words" ] } } },
{ $match: { "search_words": { $all: [ "the", "king" ] } } },
{ $project: { "search_words": 0} }
],
{ collation: { locale: "en", strength: 2 } }).pretty()
Notice the collation option is applied to the aggregation. Also, the aggregation $match stage is now using all lowercase text.
Here is the output...
{
"_id" : ObjectId("60d6139a9148371ae7d2b343"),
"book" : "The Stand",
"author" : "Stephen King"
}
{
"_id" : ObjectId("60d6139a9148371ae7d2b344"),
"book" : "The Dead Zone",
"author" : "Stephen King"
}
Beware
use of regular expressions with collation options will probably not work as expected, at least from an index strategy point of view. In my example I am not using any regular expressions ($regex), and as such it works as expected. But again, this is for exact matches, not partial matches (a.k.a. range queries) such as "Starts with 'ki*'"
MongoDB Atlas Search
If using MongoDB Atlas the use of Atlas Search solves this problem directly, with the exception of common words such as 'the' are omitted.
I have started using AWS Elastic Search Service and I want to search in JSON array object with partial string search along with Multiple word search.
For example I have added the three objects in an array.
[{
"_id" : "1",
"TitleKeywords" : "Game of thrones"
},
{
"_id" : "2",
"TitleKeywords" : "Baywatch"
},
{
"_id" : "3",
"TitleKeywords" : "Spider Man"
}]
Now I want to perform search on field name TitleKeywords and I want to search for partial word also search on multiple words.
Like for example, If I want to search 'Spi' character then it should results me into below JSON object.
{
"_id" : "3",
"TitleKeywords" : "Spider Man"
}
I have searched query syntax for this and found below query :
query: {
query_string: {
default_field: "TitleKeywords",
query: "*Spi*"
}
}
Also, for search keyword 'Spider M' (which is a multiple word search) it should result me into below JSON object :
{
"_id" : "3",
"TitleKeywords" : "Spider Man"
}
Now, if I want to search on multiple words then I can use below query :
query: {
match: {
"TitleKeywords": {
"query": "Spider M",
"operator": "and"
}
}
}
I want my result to be the mixture of both query which results into partial string search on multiple words.
Can anyone please help me on this ?
Thanks
I think you should consider using combination of multi-fields with NGram Tokenizer.
So you are adding ngram field to your "TitleKeywords" and querying this way:
query: {
match: {
"TitleKeywords.ngram": {
"query" : "Spider M",
"operator": "and"
}
}
}
But NGram-ing from 1 char can be ineffective so I'm not sure if this suits your needs.
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.
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