The below is my movie schema:
"_id" : ObjectId("59b9501600fcb397d6acd5bb"),
"theatreid" : 2,
"name" : "carnival cinemas",
"location" : "kanjulmarg",
"address" : "sec 2,kanjul, Mumbai, Maharashtra 400703",
"shows" : [
{
"mname" : "bareily ki barfi",
"timings" : [
10,
13,
14,
16,
22
]
},
{
"mname" : "Toilet:ek prem katha",
"timings" : [
8,
9,
14,
16,
20,
23
]
}
]
"_id" : ObjectId("59b9506500fcb397d6acd5bc"),
"theatreid" : 3,
"name" : "pheonix pvr",
"location" : "kurla",
"address" : "sec 26,kurla, Mumbai, Maharashtra 400701",
"shows" : [
{
"mname" : "shubh mangal savdhan",
"timings" : [
9,
11,
15,
18,
20
]
},
{
"mname" : "Toilet:ek prem katha",
"timings" : [
8,
9,
14,
16,
20,
23
]
}
]
My query is to display all the theaters having show timing (shows.timings) greater than 20 and the location is kurla.I am using nodeJS.
The query is as follows:
user.aggregate([{$match:{"location":"kurla"}},{"$addFields": {"shows": {"$map": {"input": "$shows","as": "resultm","in": {"name": "$$resultm.name","mname": "$$resultm.mname","timings": {"$filter": {"input": "$$resultm.timings","as": "resultf","cond": {"$gte": ["$$resultf",10]}}}}}}}}])
This works fine when it gets the exact match where location="kurla",but i want that it should also work and display the same records even if location=kurla east,maharashthra,mumbai.That is even if a partial match is found in the location attribute of my collection.How can this be done!Please help. Thanks:)
Use the $regex operator to apply a partial text match on the location attribute.
Replace this ...
{$match:{"location":"kurla"}}
... with this:
{ $match: {location: { $regex: /^kurla/ } } }
In the above example the condition is location like 'kurla%'.
More details in the docs.
This presumes that the values you wish to filter on are all in the location field, this is consistent with the following statement from your question:
location=kurla east,maharashthra,mumbai
There are no examples of "maharashthra" or "mumbai" in the location field in the example documents you showed however "maharashthra" does appear in the address attribute so if your filter is actually to be applied to location and/or address then the solution will be different to what I have posted above. If this is the case, perhaps you could update your question to clarify.
Related
I have a document in the below format. The goal is to group the document by student name and sort it by rank in the ascending order. Once that is done, iterate through the rank(within a student) and if each subsequent rank is greater than the previous one, the version field needs to be incremented. As part of a pipeline, student_name will be passed to me so matching by student name should be good instead of grouping.
NOTE: Tried it with python and works to some extent. A python solution would also be great!
{
"_id" : ObjectId("5d389c7907bf860f5cd11220"),
"class" : "I",
"students" : [
{
"student_name" : "AAA",
"Version" : 2,
"scores" : [
{
"value" : "50",
"rank" : 2
},
{
"value" : "70",
"rank" : 1
}
]
},
{
"student_name" : "BBB",
"Version" : 5,
"scores" : [
{
"value" : 80,
"rank" : 2
},
{
"value" : 100,
"rank" : 1
},
{
"value" : 100,
"rank" : 1
}
]
}
]
}
I tried this piece of code to sort
def version(student_name):
db.column.aggregate(
[
{"$unwind": "$students"},
{"$unwind": "$students.scores"},
{"$sort" : {"students.scores.rank" : 1}},
{"$group" : {"students.student_name}
]
)
for i in range(0,(len(students.scores)-1)):
if students.scores[i].rank < students.scores[i+1].rank:
tag.update_many(
{"$inc" : {"students.Version":1}}
)
The expected output for student AAA should be
{
"_id" : ObjectId("5d389c7907bf860f5cd11220"),
"class" : "I",
"students" : [
{
"student_name" : "AAA",
"Version" : 3, #version incremented
"scores" : [
{
"value" : "70",
"rank" : 1
},
{
"value" : "50",
"rank" : 2
}
]
}
I was able to sort the document.
pipeline = [
{"$unwind": "$properties"},
{"$unwind": "$properties.values"},
{"$sort" : {"$properties.values.rank" : -1}},
{"$group": {"_id" : "$properties.property_name", "values" : {"$push" : "$properties.values"}}}
]
import pprint
pprint.pprint(list(db.column.aggregate(pipeline)))
Below if a document from my collection of over 20,000,000 documents.
I need to find documents by a particular zip, out of these documents I need to select one record from each postal address (ADDR, CITY, STATE, ZIP, APT) and which has a age value of 18 or higher.
The results need to be limited to a number as well which is entered by the end-user.
{
"_id" : ObjectId("55e86e98f493590878bb45d7"),
"RecordID" : 84096380,
"FN" : "Michael",
"MI" : "",
"LN" : "Horn",
"NAME_PRE" : "MR",
"ADDR" : "160 Yankee Camp Rd",
"CITY" : "Telford",
"ST" : "TN",
"ZIP" : 37690,
"APT" : "",
"Z4" : 2200,
"DPC" : 605,
"CAR_RTE" : "R001",
"WALK_SEQ" : 228,
"LOT" : "0136A",
"FIPS_ST" : 47,
"FIPS_CTY" : 179,
"LATITUDE" : 36.292787,
"LONGITUDE" : -82.568171,
"ADDR_TYP" : 1,
"MSA" : 3660,
"CBSA" : 27740,
"ADDR_LINE" : 3,
"DMA_SUPPR" : "",
"GEO_MATCH" : 1,
"CENS_TRACT" : 61900,
"CENS_BLK_GRP" : 1,
"CENS_BLK" : 17,
"CENS_MED_HOME_VALUE" : 953,
"CENS_MED_HH_INCOME" : 304,
"CRA" : "",
"Z4_TYP" : "S",
"DSF_IND" : 1,
"DPD_IND" : "N",
"PHONE_FLAG" : "Y",
"PHONE" : NumberLong("4237730233"),
"TIME_ZN" : "E",
"GENDER" : "M",
"NEW_TO_BLD" : "",
"SOURCES" : 19,
"BASE_VER_DT" : 20101,
"COMP_ID" : NumberLong("3769001836"),
"IND_ID" : 1,
"INF_HH_RANK" : 1,
"HOME_OWNR_SRC" : "V",
"DOB_YR" : 1975,
"DOB_MON" : 7,
"DOB_DAY" : 10,
"EXACT_AGE" : 39,
"AGE" : 39,
"HH_INCOME" : "D"
}
if you are using mongoose, we can chain the operations by dot(.) operator. Since i see all your needs is conditional here is the example -
Person.
find({
ZIP: "37690",
ADDR : "",
STATE : "", //so on
AGE: { $gt: 18 }
}).
limit(10).
exec(callback);
more info - http://mongoosejs.com/docs/queries.html
You need to use aggregate operation.
var pipeline = [
{
$match: {ZIP: 37690, AGE: {$gt: 18}}
}, {
$group: {
_id: {ADDR: '$ADDR', CITY: '$CITY', STATE: '$STATE', ZIP: '$ZIP', APT: '$APT'},
PHONE: {$first: '$PHONE'}
}
},
{$limit: 10}
];
db.mycoll.aggregate(pipeline)
enhance the above to project whatever fields you require in results
I think This query will solve your problem.
Person.find({
ZIP: "37690",
AGE: { $gt: 18 }
}).
limit(50).
exec(callback);
{
"_id" : ObjectId("5514ecc73910d3e808b9417c"),
"endingReciptBookNumber" : 2999,
"startingReciptBookNumber" : 2900,
"User" : 8,
"allRecipt" : [
{
"recipt_Number" : 2999,
"amount" : 24124,
"_id" : ObjectId("5514ecc73910d3e808b94180")
},
{
"recipt_Number" : 100,
"amount" : 2414,
"_id" : ObjectId("5514ecc73910d3e808b9417f")
},
{
"recipt_Number" : 101,
"amount" : 242,
"_id" : ObjectId("5514ecc73910d3e808b9417e")
},
{
"recipt_Number" : 102,
"amount" : 2424,
"_id" : ObjectId("5514ecc73910d3e808b9417d")
}
],
"__v" : 0
}
I have many documents like this in a collection in mongoose .I want to find a latest entered recipt_Number for a particular user. like in this case it should give me 102 as answer.
i have also attached snippet of lines of code. Its also a way to get same result.
db.topics.find( {'User': 8}, { 'allRecipt': { $slice: -1 },'startingReciptBookNumber':0,'endingReciptBookNumber':0,'User':0,'_id':0,'__v':0 } )
query result like below
{
"allRecipt" : [
{
"recipt_Number" : 102,
"amount" : 2424,
"_id" : ObjectId("5514ecc73910d3e808b9417d")
}
]
}
Though query won't give any single number in result but it will give desired outcome through result.allRecipt.0.recipt_Number, Your desired number will always get into in 0 index. I think this is your desired number.
Here $slice make a difference.
Thanks
So I have a set of data that have timestamps associated with it. I want mongo to aggregate the ones that have duplicates within a 3 min timestamp. I'll show you an example of what I mean:
Original Data:
[{"fruit" : "apple", "timestamp": "2014-07-17T06:45:18Z"},
{"fruit" : "apple", "timestamp": "2014-07-17T06:47:18Z"},
{"fruit" : "apple", "timestamp": "2014-07-17T06:55:18Z"}]
After querying, it would be:
[{"fruit" : "apple", "timestamp": "2014-07-17T06:45:18Z"},
{"fruit" : "apple", "timestamp": "2014-07-17T06:55:18Z"}]
Because the second entry was within the 3 min bubble created by the first entry. I've gotten the code so that it aggregates and removed dupes that have the same fruit but now I only want to combine the ones that are within the timestamp bubble.
We should be able to do this! First lets split up an hour in 3 minute 'bubbles':
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57]
Now to group these documents we need to modify the timestamp a little. As far I as know this isn't currently possible with the aggregation framework so instead I will use the group() method.
In order to group fruits within the same time period we need to set the timestamp to the nearest minute 'bubble'. We can do this with timestamp.minutes -= (timestamp.minutes % 3).
Here is the resulting query:
db.collection.group({
keyf: function (doc) {
var timestamp = new ISODate(doc.timestamp);
// seconds must be equal across a 'bubble'
timestamp.setUTCSeconds(0);
// round down to the nearest 3 minute 'bubble'
var remainder = timestamp.getUTCMinutes() % 3;
var bubbleMinute = timestamp.getUTCMinutes() - remainder;
timestamp.setUTCMinutes(bubbleMinute);
return { fruit: doc.fruit, 'timestamp': timestamp };
},
reduce: function (curr, result) {
result.sum += 1;
},
initial: {
sum : 0
}
});
Example results:
[
{
"fruit" : "apple",
"timestamp" : ISODate("2014-07-17T06:45:00Z"),
"sum" : 2
},
{
"fruit" : "apple",
"timestamp" : ISODate("2014-07-17T06:54:00Z"),
"sum" : 1
},
{
"fruit" : "banana",
"timestamp" : ISODate("2014-07-17T09:03:00Z"),
"sum" : 1
},
{
"fruit" : "orange",
"timestamp" : ISODate("2014-07-17T14:24:00Z"),
"sum" : 2
}
]
To make this easier you could precompute the 'bubble' timestamp and insert it into the document as a separate field. The documents you create would look something like this:
[
{"fruit" : "apple", "timestamp": "2014-07-17T06:45:18Z", "bubble": "2014-07-17T06:45:00Z"},
{"fruit" : "apple", "timestamp": "2014-07-17T06:47:18Z", "bubble": "2014-07-17T06:45:00Z"},
{"fruit" : "apple", "timestamp": "2014-07-17T06:55:18Z", "bubble": "2014-07-17T06:54:00Z"}
]
Of course this takes up more storage. However, with this document structure you can use the aggregate function[0].
db.collection.aggregate(
[
{ $group: { _id: { fruit: "$fruit", bubble: "$bubble"} , sum: { $sum: 1 } } },
]
)
Hope that helps!
[0] MongoDB aggregation comparison: group(), $group and MapReduce
I'm trying to query into following document and want to list all document which contains TaxonomyID "1" in "TaxonomyIDs" field.
...
"Slug" : "videosecu-600tvl-outdoor-security-surveillance",
"Category" : "Digital Cameras",
"SubCategory" : "Surveillance Cameras",
"Segment" : "",
"Usabilities" : [
"Dome Cameras",
"Night Vision"
],
"TaxonomyIDs" : [
1,
12,
20,
21,
13
],
"Brand" : "VideoSecu",
...
Totally stuck!
Model.find({TaxonomyIDs: 1}, function(error, models) {
//put code to process the results here
});
mongodb interprets the query conditions above as "match any document where the TaxonomyIDs array contains 1".