mongodb mapreduce exclude nested field - mongodb

I am mongodb newbie! I am trying to process some tweeter data. my goal is to group users on each time interval (for simplicity, daily interval) and count his unique hashtags on that day. My idea to build new DB which is only contains user, date and hashtags. Here is data format:
> db.sampledDB.findOne()
{
"_id" : NumberLong("2334234"),
"replyid" : NumberLong(-1),
"userid" : NumberLong(21313),
"replyuserid" : NumberLong(-1),
"createdAt" : ISODate("2013-07-02T22:35:06Z"),
"tweettext" : "RT #BBCBreaking: Plane carrying Bolivia President Morales is diverted to Austria on suspicion US fugitive #Snowden is on board - Bolivian m…",
"screenName" : "x83",
"name" : "david x",
"retweetCount" : NumberLong(0),
"retweet_id" : NumberLong("12313223"),
"retweet_userid" : NumberLong(123123123),
"source" : "Twitter for Windows Phone",
"hashtags" : [
{
"start" : 106,
"end" : 114,
"text" : "Snowden"
}
],
"mentions" : [
{
"start" : 3,
"end" : 15,
"id" : NumberLong(876678),
"screenName" : "BBCBreaking",
"name" : "BBC Breaking News"
}
],
"media" : [ ]
}
I use mapReduce like this:
MAP:
map = function(){
//format date to year/month/day
var format = this.createdAt.getFullYear() + '/' + (this.createdAt.getMonth()+1) + '/' + this.createdAt.getDate();
var key = {userid:this.userid, date:format};
emit(key,{hashtags:this.hashtags}); }
REDUCE:
reduce = function(key,values){
var result = {a:[]};
for (var idx=0;idx<values.length;idx++){
result.a.push(values[idx].hashtag);
}
return result};
it results to:
{
"_id" : {
"userid" : NumberLong(7686787),
"date" : "2013/7/5"
},
"value" : {
"hashtag" : [
{
"start" : 24,
"end" : 44,
"text" : "SıkSöylenenYalanlar"
},
{
"start" : 45,
"end" : 60,
"text" : "ZimmermanTrial"
},
{
"start" : 61,
"end" : 84,
"text" : "ZaynMalikYouArePerfect"
},
{
"start" : 85,
"end" : 99,
"text" : "TrayvonMartin"
},
{
"start" : 100,
"end" : 110,
"text" : "Wimbledon"
},
{
"start" : 111,
"end" : 118,
"text" : "Футбол"
},
{
"start" : 119,
"end" : 127,
"text" : "Snowden"
},
{
"start" : 128,
"end" : 138,
"text" : "TFFistifa"
}
]
}
},
{
"_id" : {
"userid" : NumberLong(45666),
"date" : "2013/7/5"
},
"value" : {
"hashtag" : [
{
"start" : 24,
"end" : 44,
"text" : "SıkSöylenenYalanlar"
},
{
"start" : 45,
"end" : 60,
"text" : "ZimmermanTrial"
},
{
"start" : 61,
"end" : 84,
"text" : "ZaynMalikYouArePerfect"
},
{
"start" : 85,
"end" : 99,
"text" : "TrayvonMartin"
},
{
"start" : 100,
"end" : 110,
"text" : "Wimbledon"
},
{
"start" : 111,
"end" : 118,
"text" : "Футбол"
},
{
"start" : 119,
"end" : 127,
"text" : "Snowden"
},
{
"start" : 128,
"end" : 138,
"text" : "TFFistifa"
}
]
}
},
But I just want to keep the text element of hashtags. I tried to change the reducer to values[idx].hashtag.text or values[idx].hashtag["text"] which did not help.
UPDATE:
I suspect my problem is similar to MapReduce problem, but I dont know to fix mine

You might also consider using the aggregation framework which can produce the results shown below. The pipeline would look similar to this:
{$project: {
userid: "$userid",
"hashtags": "$hashtags.text",
date: {
year: { $year: "$createdAt" },
month: { $month: "$createdAt"},
day: {$dayOfMonth: "$createdAt"} }}},
{$unwind: "$hashtags" },
{ $group: { _id : {
date: "$date",
userid: "$userid"},
hashtags: { $addToSet:"$hashtags" }
}} )
Might produce a result like:
[
{
"_id" : {
"date" : {
"year" : 2013,
"month" : 8,
"day" : 4
},
"userid" : NumberLong(362337301)
},
"hashtags" : [
"tagger",
"stackoverflow",
"twitter"
]
}, /* more */
A brief explanation of the aggregation framework pipeline:
Using $project, grab only the fields that will matter through the rest of the pipeline. Before doing this, if there was a specific date or range that would have been desired, using $match would have been a great step to filter some of the results efficiently). Note that the createdAt field has been split into the respective pieces so that the time of day will later be ignored when grouping. After the projection has occurred, the new field will be called date in the example. Here, the hash tags have been simplified to be only the text property, and the name reused as "hashtags".
Next, as "hashtags" is an array at this point (would look like: ['tagger', 'stackoverflow', 'twitter'] for example, the pipeline creates a new document for each element in the "hashtag" array.
Finally, the grouping pipeline operator uses the combination of userid and date as a grouper, and adds all unique hash tags to a field called "hashtags".
As an alternative to splitting the date, you can also just treat the createdAt field as a string, and remove the time by using this in the pipeline:
date: {$substr: ["$createdAt",0, 10] }
It would produce something like:
2013-07-02
Edit
As you've pointed out, there is currently a 16MB limit in the document that is output from an Aggregation. While this is scheduled to be changed in the 2.6 version of MongoDB, you may be able to get a MapReduce as well that work. It's a bit messier given a MapReduce wasn't necessarily intended for this type of work, so the results may not be necessarily what you want.
map = function() {
var format = this.createdAt.getFullYear() + '/'
+ (this.createdAt.getMonth()+1) + '/' + this.createdAt.getDate();
var key = {userid:this.userid, date:format};
var hashtags = this.hashtags || [];
for(var i=0, l=hashtags.length; i < l; i++) {
emit(key, hashtags[i].text);
}
};
reduce = function(key, values){
values = values || [];
var tag;
var tags = {};
for(var i=0, l=values.length; i<l ; i++) {
tag = values[i] || "";
if (tag.length > 0) {
tags[tag] = "";
}
};
values = [];
for(var t in tags) {
values.push(t);
}
return values.join(',');
};
Instead of emitting the array, it emits each hash tag in the map. The reduce eliminates duplicates using a simple associative array and then returns a joined string with all of the hash tags. MongoDB does not support returning an array of results via the reduce function (the idea is that a reduce should be providing one result, not an array of results).
Results:
{
"_id" : {
"userid" : NumberLong(262317302),
"date" : "2013/7/2"
},
"value" : "Wisconsin,Space,Cheese"
}
If you don't need to do this work frequently, you could also just write a shell script in the MongoDB console that extracts the hash tags into a new collection. Then, just run it when you need to.

here is how I managed to produce the same result as the answer above. just for presenting another solution.
map = function(){
var day = this.createdAt.getFullYear() + '/' + (this.createdAt.getMonth()+1) + '/' + this.createdAt.getDate();
var key = {userid:this.userid, date:day};
var values = {hashtags:[]};
for (var idx=0;idx<this.hashtags.length;idx++){
values.hashtags.push(this.hashtags[idx].text);
}
emit(key,values);
};
reduce = function(key,values){
hashtag_list = {hashtags: []} ;
for(var i in values) {
hashtag_list.hashtags= values[i].hashtags.concat(hashtag_list.hashtags);
}
return hashtag_list;
}

Try:
values[idx].text
hashtag is not a property of the object, but text is.

Related

Querying with array of parameters in mongodb

I have below collection in the DB, I want to retrieve data where birth month equal to given 2 months. lets say [1,2], or [4,5]
{
"_id" : ObjectId("55aa1e526fea82e9a4188f38"),
"name" : "Nilmini",
"birthDate" : 6,
"birthMonth" : 1
},
{
"_id" : ObjectId("55aa1e526fea82e9a4188f39"),
"name" : "Ruwan",
"birthDate" : 6,
"birthMonth" : 1
},{
"_id" : ObjectId("55aa1e526fea82e9a4188f40"),
"name" : "Malith",
"birthDate" : 6,
"birthMonth" : 1
},
{
"_id" : ObjectId("55aa1e526fea82e9a4188f7569"),
"name" : "Pradeep",
"birthDate" : 6,
"birthMonth" : 7
}
I use below query to get the result set, I could get the result for give one month,now I want to get results for multiple months.
var currentDay = moment().date();
var currentMonths = [];
var currentMonth = moment().month();
if(currentDay > 20){
currentMonths.push(moment().month());
currentMonths.push(moment().month()+1);
}else{
currentMonths.push(currentMonth);
}
// In blow query I am trying to pass the array to the 'birthMonth',
I'm getting nothing when I pass array to the query, I think there should be another way to do this,
Employee.find(
{
"birthDate": {$gte:currentDay}, "birthMonth": currentMonths
}, function(err, birthDays) {
res.json(birthDays);
});
I would really appreciate if you could help me to figure this out
You can use the $in operator to match against multiple values in an array like currentMonths.
So your query would be:
Employee.find(
{
"birthDate": {$gte:currentDay}, "birthMonth": {$in: currentMonths}
}, function(err, birthDays) {
res.json(birthDays);
});

get undefined value in mongodb MapReduce

I tried to use twice MapReduce aggregation to get unique user number per month.
The first MR function work out a mr_buyer_payment collection, like this:
{ "_id" : { "u" : "01329f19-27b0-435b-9ca1-450984024a31", "tid" : ISODate("2013-09-01T00:00:00Z") }, "value" : { "payment" : 38, "count_pay" : 1 } }
{ "_id" : { "u" : "264dd104-b934-490b-988e-5822fd7970f6", "tid" : ISODate("2013-09-01T00:00:00Z") }, "value" : { "payment" : 4.99, "count_pay" : 1 } }
{ "_id" : { "u" : "27bb8f72-a13e-4676-862c-02f41fea1bc0", "tid" : ISODate("2013-09-01T00:00:00Z") }, "value" : { "payment" : 11.98, "count_pay" : 2 } }
The second MR function works well with small data set , but when query grows more than 100 records, it gets wrong result , some value is NaN.
The debug log shows some value in Reduce function like v.payment, v.count_user became undefine.
date:Sun Jun 30 2013 17:00:00 GMT-0700 (PDT) value:undefined / 162 / undefined
And the MR result info is wired:
{
"result" : "mr_buyer_all",
"timeMillis" : 29,
"counts" : {
"input" : 167,
"emit" : 167,
"reduce" : 6, // it should be 3, as same as "output" number
"output" : 3
},
"ok" : 1,
}
This is 2nd MR function:
db.mr_buyer_payment.mapReduce(
function(){
var key = this._id.tid;
var value = {
payment:this.value.payment,
count_pay:this.value.count_pay,
count_user:1
};
if (value.count_pay>0)
{
print("date:"+key+" u:"+this._id.u+"value:"+value.payment+" / "+value.count_pay+" / "+value.count_user);
emit(key,value);
}
},
function(key,values){
var result = {revenue:0,count_pay:0,user:0};
values.forEach(function(v){
if (!v.count_user)
{
print("date:"+key+" "+"value:"+v.payment+" / "+v.count_pay+" / "+v.count_user);
} else
{
result.revenue += v.payment;
result.count_pay += v.count_pay;
result.user += v.count_user;
}
});
return result;
},
{
out:{replace:"mr_buyer_all"}
}
)
The sub-document in Reduce function should use same format as one in Map function. So the solution is :
function(key,values){
// the following key must be as same as the object in map
var r = {payment:0,count_pay:0,count_user:0}
values.forEach(function(v){
r.payment += v.payment;
r.count_pay += v.count_pay;
r.count_user += v.count_user;
});
return r;
},

Update an element in sub of sub array in mongodb

I have this data in Mongo:
{
"_id" : ObjectId("505fd43fdbed3dd93f0ae088"),
"categoryName" : "Cat 1",
"services" : [
{
"serviceName" : "Svc 1",
"input" : [
{ "quantity" : 10, "note" : "quantity = 10" },
{ "quantity" : 20, "note" : "quantity = 20" }
]
},
{
"serviceName" : "Svc 2",
"input" : [
{ "quantity" : 30, "note" : "quantity = 30" },
{ "quantity" : 40, "note" : "quantity = 40" }
]
}
]
}
Now I want to update a quantity for "Svc 1":
{ "quantity" : 10, "note" : "quantity = 10" }
Like:
{"quantity": 100, "note": "changed to 100"}
How can I do with Mongo?`
As I know, operational operator only supports for the first array, someone advised to use index of an element of the sub sub array, but the problem is that how can know that index at run time? (I'm using native C# driver of MongoDB)
Thanks in advance for your helps!
Johnny
Since you have an array within an array, there isn't any easy way to reference the nested subarray unless you know the position in the array you want to update.
So, for example, you could update the first input for 'Svc 1' with the C# equivalent of:
db.services.update(
// Criteria
{
'_id' : ObjectId("505fd43fdbed3dd93f0ae088"),
'services.serviceName' : 'Svc 1'
},
// Updates
{
$set : {
'services.$.input.0.quantity' : 100,
'services.$.input.0.note' : 'Quantity updated to 100'
}
}
)
If you don't know the position for the nested input array, you will have to fetch the matching services, iterate the input array in your application code, then $set the updated array.
Alternatively, you could modify your nested array to use an embedded document instead, eg:
{
"categoryName" : "Cat 1",
"services" : [
{
"serviceName" : "Svc 1",
"input1" : { "quantity" : 10, "note" : "quantity = 10" },
"input2" : { "quantity" : 20, "note" : "quantity = 20" }
},
]
}
Which you could then update by name, eg input1:
db.services.update(
// Criteria
{
'_id' : ObjectId("5063e80a275c457549de2362"),
'services.serviceName' : 'Svc 1'
},
// Updates
{
$set : {
'services.$.input1.quantity' : 100,
'services.$.input1.note' : 'Quantity updated to 100'
}
}
)
Since you don't know the position of the value wanted to update, first insert a new value with updated information and then remove the value wanted to update.
db.services.update(
{
'_id' : ObjectId("505fd43fdbed3dd93f0ae088"),
'services.serviceName' : 'Svc 1'
},
{
{ $addToSet: { 'services.$.input' : "new sub-Doc" }
}
)
And then remove when insert is success
db.services.update(
{
'_id' : ObjectId("505fd43fdbed3dd93f0ae088"),
'services.serviceName' : 'Svc 1'
},
{
{ $pull: { 'services.$.input' : { "quantity" : 10, "note" : "quantity = 10" } }
}
)
This is useful when index is not known and document should have sub-documents having same key like "input" in post Update an element in sub of sub array in mongodb

MongoDB - how to query for a nested item inside a collection?

I have some data that looks like this:
[
{
"_id" : ObjectId("4e2f2af16f1e7e4c2000000a"),
"advertisers" : [
{
"created_at" : ISODate("2011-07-26T21:02:19Z"),
"category" : "Infinity Pro Spin Air Brush",
"updated_at" : ISODate("2011-07-26T21:02:19Z"),
"lowered_name" : "conair",
"twitter_name" : "",
"facebook_page_url" : "",
"website_url" : "",
"user_ids" : [ ],
"blog_url" : "",
},
and I was thinking that a query like this would give the id of the advertiser:
var start = new Date(2011, 1, 1);
> var end = new Date(2011, 12, 12);
> db.agencies.find( { "created_at" : {$gte : start , $lt : end} } , { _id : 1 , program_ids : 1 , advertisers { name : 1 } } ).limit(1).toArray();
But my query didn't work. Any idea how I can add the fields inside the nested elements to my list of fields I want to get?
Thanks!
Use dot notation (e.g. advertisers.name) to query and retrieve fields from nested objects:
db.agencies.find({
"advertisers.created_at": {
$gte: start,
$lt: end
}
},
{
_id: 1,
program_ids: 1,
"advertisers.name": 1
}
}).limit(1).toArray();
Reference: Retrieving a Subset of Fields
and Dot Notation
db.agencies.find(
{ "advertisers.created_at" : {$gte : start , $lt : end} } ,
{ program_ids : 1 , advertisers.name : 1 }
).limit(1).pretty();
There is one thing called dot notation that MongoDB provides that allows you to look inside arrays of elements. Using it is as simple as adding a dot for each array you want to enter.
In your case
"_id" : ObjectId("4e2f2af16f1e7e4c2000000a"),
"advertisers" : [
{
"created_at" : ISODate("2011-07-26T21:02:19Z"),
"category" : "Infinity Pro Spin Air Brush",
"updated_at" : ISODate("2011-07-26T21:02:19Z"),
"lowered_name" : "conair",
"twitter_name" : "",
"facebook_page_url" : "",
"website_url" : "",
"user_ids" : [ ],
"blog_url" : "",
},
{ ... }
If you want to go inside the array of advertisers to look for the property created_at inside each one of them, you can simply write the query with the property {'advertisers.created_at': query} like follows
db.agencies.find( { 'advertisers.created_at' : { {$gte : start , $lt : end} ... }

Merging two collections in MongoDB

I've been trying to use MapReduce in MongoDB to do what I think is a simple procedure. I don't know if this is the right approach, of if I should even be using MapReduce. I googled what keywords I thought of and tried to hit the docs where I thought I would have the most success - but nothing. Maybe I'm thinking too hard about this?
I have two collections: details and gpas
details is made up of a whole bunch of documents (3+ million). The studentid element can be repeated two times, one for each year, like the following:
{ "_id" : ObjectId("4d49b7yah5b6d8372v640100"), "classes" : [1,17,19,21], "studentid" : "12345a", "year" : 1}
{ "_id" : ObjectId("4d76b7oij7s2d8372v640100"), "classes" : [2,12,19,22], "studentid" : "98765a", "year" : 1}
{ "_id" : ObjectId("4d49b7oij7s2d8372v640100"), "classes" : [32,91,101,217], "studentid" : "12345a", "year" : 2}
{ "_id" : ObjectId("4d76b7rty7s2d8372v640100"), "classes" : [1,11,18,22], "studentid" : "24680a", "year" : 1}
{ "_id" : ObjectId("4d49b7oij7s2d8856v640100"), "classes" : [32,99,110,215], "studentid" : "98765a", "year" : 2}
...
gpas has elements with the same studentid's from details. Only one entry per studentid, like this:
{ "_id" : ObjectId("4d49b7yah5b6d8372v640111"), "studentid" : "12345a", "overall" : 97, "subscore": 1}
{ "_id" : ObjectId("4f76b7oij7s2d8372v640213"), "studentid" : "98765a", "overall" : 85, "subscore": 5}
{ "_id" : ObjectId("4j49b7oij7s2d8372v640871"), "studentid" : "24680a", "overall" : 76, "subscore": 2}
...
In the end I want to have a collection with one row for each student in this format:
{ "_id" : ObjectId("4d49b7yah5b6d8372v640111"), "studentid" : "12345a", "classes_1": [1,17,19,21], "classes_2": [32,91,101,217], "overall" : 97, "subscore": 1}
{ "_id" : ObjectId("4f76b7oij7s2d8372v640213"), "studentid" : "98765a", "classes_1": [2,12,19,22], "classes_2": [32,99,110,215], "overall" : 85, "subscore": 5}
{ "_id" : ObjectId("4j49b7oij7s2d8372v640871"), "studentid" : "24680a", "classes_1": [1,11,18,22], "classes_2": [], "overall" : 76, "subscore": 2}
...
The way I was going to do this was by running MapReduce like this:
var mapDetails = function() {
emit(this.studentid, {studentid: this.studentid, classes: this.classes, year: this.year, overall: 0, subscore: 0});
};
var mapGpas = function() {
emit(this.studentid, {studentid: this.studentid, classes: [], year: 0, overall: this.overall, subscore: this.subscore});
};
var reduce = function(key, values) {
var outs = { studentid: "0", classes_1: [], classes_2: [], overall: 0, subscore: 0};
values.forEach(function(value) {
if (value.year == 0) {
outs.overall = value.overall;
outs.subscore = value.subscore;
}
else {
if (value.year == 1) {
outs.classes_1 = value.classes;
}
if (value.year == 2) {
outs.classes_2 = value.classes;
}
outs.studentid = value.studentid;
}
});
return outs;
};
res = db.details.mapReduce(mapDetails, reduce, {out: {reduce: 'joined'}})
res = db.gpas.mapReduce(mapGpas, reduce, {out: {reduce: 'joined'}})
But when I run it, this is my resulting collection:
{ "_id" : "12345a", "value" : { "studentid" : "12345a", "classes_1" : [ ], "classes_2" : [ ], "overall" : 97, "subscore" : 1 } }
{ "_id" : "98765a", "value" : { "studentid" : "98765a", "classes_1" : [ ], "classes_2" : [ ], "overall" : 85, "subscore" : 5 } }
{ "_id" : "24680a", "value" : { "studentid" : "24680a", "classes_1" : [ ], "classes_2" : [ ], "overall" : 76, "subscore" : 2 } }
I'm missing the classes arrays.
Also, as an aside, how do I access the elements in resulting MapReduce value element? Does MapReduce always output to value or whatever else you name it?
This is similar to a question that was asked on the MongoDB-users Google Groups.
https://groups.google.com/group/mongodb-user/browse_thread/thread/60a8b683e2626ada?pli=1
The answer references an on-line tutorial which looks similar to your example:
http://tebros.com/2011/07/using-mongodb-mapreduce-to-join-2-collections/
For more information on MapReduce in MongoDB, please see the documentation:
http://www.mongodb.org/display/DOCS/MapReduce
Additionally, there is a useful step-by-step walkthrough of how a MapReduce operation works in the "Extras" Section of the MongoDB Cookbook article titled, "Finding Max And Min Values with Versioned Documents":
http://cookbook.mongodb.org/patterns/finding_max_and_min/
Forgive me if you have already read some of the referenced documents. I have included them for the benefit of other users who may be reading this post and new to using MapReduce in MongoDB
It is important that the outputs from the 'emit' statements in the Map functions match the outputs of the Reduce function. If there is only one document output by the Map function, the Reduce function might not be run at all, and then your output collection will have mismatched documents.
I have slightly modified your map statements to emit documents in the format of your desired output, with two separate "classes" arrays.
I have also reworked your reduce statement to add new classes to the classes_1 and classes_2 arrays, only if they do not already exist.
var mapDetails = function(){
var output = {studentid: this.studentid, classes_1: [], classes_2: [], year: this.year, overall: 0, subscore: 0}
if (this.year == 1) {
output.classes_1 = this.classes;
}
if (this.year == 2) {
output.classes_2 = this.classes;
}
emit(this.studentid, output);
};
var mapGpas = function() {
emit(this.studentid, {studentid: this.studentid, classes_1: [], classes_2: [], year: 0, overall: this.overall, subscore: this.subscore});
};
var r = function(key, values) {
var outs = { studentid: "0", classes_1: [], classes_2: [], overall: 0, subscore: 0};
values.forEach(function(v){
outs.studentid = v.studentid;
v.classes_1.forEach(function(class){if(outs.classes_1.indexOf(class)==-1){outs.classes_1.push(class)}})
v.classes_2.forEach(function(class){if(outs.classes_2.indexOf(class)==-1){outs.classes_2.push(class)}})
if (v.year == 0) {
outs.overall = v.overall;
outs.subscore = v.subscore;
}
});
return outs;
};
res = db.details.mapReduce(mapDetails, r, {out: {reduce: 'joined'}})
res = db.gpas.mapReduce(mapGpas, r, {out: {reduce: 'joined'}})
Running the two MapReduce operations results in the following collection, which matches your desired format:
> db.joined.find()
{ "_id" : "12345a", "value" : { "studentid" : "12345a", "classes_1" : [ 1, 17, 19, 21 ], "classes_2" : [ 32, 91, 101, 217 ], "overall" : 97, "subscore" : 1 } }
{ "_id" : "24680a", "value" : { "studentid" : "24680a", "classes_1" : [ 1, 11, 18, 22 ], "classes_2" : [ ], "overall" : 76, "subscore" : 2 } }
{ "_id" : "98765a", "value" : { "studentid" : "98765a", "classes_1" : [ 2, 12, 19, 22 ], "classes_2" : [ 32, 99, 110, 215 ], "overall" : 85, "subscore" : 5 } }
>
MapReduce always outputs documents in the form of {_id:"id", value:"value"}
There is more information available on working with sub-documents in the document titled, "Dot Notation (Reaching into Objects)":
http://www.mongodb.org/display/DOCS/Dot+Notation+%28Reaching+into+Objects%29
If you would like the output of MapReduce to appear in a different format, you will have to do that programmatically in your application.
Hopefully this will improve your understanding of MapReduce, and get you one step closer to producing your desired output collection. Good Luck!
You cannot use m/r for this since that is designed to only apply on one collection. Reading from more than one collection will break sharding compatibility and is therefore not allowed. You can do what you want with either the new aggregation framework (2.1+) or do this inside your application.