I have a Collection that contains some event reported by client, such as:
{ "_id" : ObjectId("54f43159c922ac0b4387ef9c"), "appversion" : "v1.2", "appid" : "930370913", "clkip" : "", "actip" : "", "clktime" : 1425289561, "acttime" : 0, "platform" : "google", "isnotified" : false, "idfa" : "14A900D9-A61A-41DC-A327-96EBE4BA57B31" }
{ "_id" : ObjectId("54f43159c922ac0b4387ef9d"), "appversion" : "v1.2", "appid" : "930370913", "clkip" : "", "actip" : "", "clktime" : 1425289561, "acttime" : 0, "platform" : "google", "isnotified" : false, "idfa" : "14A900D9-A61A-41DC-A327-96EBE4BA57B32" }
{ "_id" : ObjectId("54f43159c922ac0b4387ef9e"), "appversion" : "v1.2", "appid" : "930370913", "clkip" : "", "actip" : "", "clktime" : 1425289561, "acttime" : 0, "platform" : "facebook", "isnotified" : false, "idfa" : "14A900D9-A61A-41DC-A327-96EBE4BA57B33" }
{ "_id" : ObjectId("54f43159c922ac0b4387ef9f"), "appversion" : "v1.2", "appid" : "930370913", "clkip" : "", "actip" : "", "clktime" : 1425289561, "acttime" : 0, "platform" : "google", "isnotified" : false, "idfa" : "14A900D9-A61A-41DC-A327-96EBE4BA57B34" }
You can see that clktime is a unix timestamp (self defined, not the one Mongodb generated) with the precision of Second, I want to know how many events per 5 mins each paltform has reported(by clktime), I know I should use mongodb's Aggregate framework such as:
db.event.aggregate([{$match:{clktime:{$gt:1425204775}}},{$group:{_id:???, count:{$sum:1}}}])
^^^
I really don't know what this _id should be.
But I don't know how to define the _id of $group :-(
The output I want to achieve is like this:
{ "_id" : 0, "time":1425207775, "count" : 100 }
{ "_id" : 0, "time":1425210775, "count" : 51 }
{ "_id" : 0, "time":1425213775, "count" : 51 }
It will be nicer if the platform information could be identified too. But if it's too complex, You can give some reference and I will dig into it myself.
Any suggestion will be appreciate.
Not a problem really and not too hard. You just need "date math" to work with the "5 minute intervals" that you describe since this is a "number" and not a "date" value. It's still possible with "Date" objects ( which you should really be using because there is little to no overhead and not much difference in processing ) but let's stick to the point:
db.event.aggregate([
{ "$match": { "clktime":{ "$gt": 1425204775 } } },
{ "$group": {
"_id": {
"$subtract": [
"$clktime",
"$mod": [ "$clktime", 60 * 5 ] // 5 minutes in seconds
]
},
"count": { "$sum": 1 }
}}
])
Rounding out the values to 5 minute intervals gets the grouping data you want in the _id grouping key.
Also the _id value is the "grouping key", so your expected result is not valid and it can only be something that is "uniquely grouped" upon. This is not really any different to SQL "GROUP BY" if you are familiar with that.
Related
I have a mongoose document that is a User. Each user has arrays or words e.g. nouns. I want to be able to update the fields of the words e.g. add a +1 to the frequency or change the status number. I can access the whole array but not the individual items in the array. Also i want to be able to display the items in the array based on their fields e.g. only display those with frequency of 3 or more etc...
I have tried lots of different things but I'm just not getting it. I keep getting back error messages that findOneAndUpdate is not a function, or 'undefined' when I try to access and update documents.
{
"_id" : ObjectId("5f7d8490c1842471c6bcea42"),
"username" : "eric#mail.com",
"nouns" : [
{
"_id" : ObjectId("5f7d849cc1842471c6bcea43"),
"word" : "die Sonne",
"timeStamp" : ISODate("2020-10-07T09:04:28.436Z"),
"frequency" : 0,
"status" : 0
},
{
"_id" : ObjectId("5f7d84a8c1842471c6bcea45"),
"word" : "das Wetter",
"timeStamp" : ISODate("2020-10-07T09:04:40.940Z"),
"frequency" : 0,
"status" : 0
},
{
"_id" : ObjectId("5f7d84afc1842471c6bcea47"),
"word" : "der Apfel",
"timeStamp" : ISODate("2020-10-07T09:04:47.403Z"),
"frequency" : 0,
"status" : 0
},
{
"_id" : ObjectId("5f7d84b9c1842471c6bcea49"),
"word" : "das Maedchen",
"timeStamp" : ISODate("2020-10-07T09:04:57.388Z"),
"frequency" : 0,
"status" : 0
},
{
"_id" : ObjectId("5f7d84c8c1842471c6bcea4b"),
"word" : "das Auto",
"timeStamp" : ISODate("2020-10-07T09:05:12.036Z"),
"frequency" : 0,
"status" : 0
}
],
"verbs" : [],
"adjectives" : [],
"others" : [],
"salt" : "*****",
"hash" : "*****",
"__v" : 5
}
figured it out after hours
const ObjectId = require('mongodb').objectID
db.collections.users.updateOne(
{},
{$set: {"nouns.$[element].status": 3}},
{multi: true,
arrayFilters: [{"element._id":
ObjectId(req.body.inputId)}]}
);
I am trying to remove a nested objects array in my document. The scenario is that i am searching for the days an event will be organised for, by using its eventid
const { eventid, typesOfTicketId } = req.params;
const eventDays = await EventDate.find({event: eventid});
Here eventid is passed from params as "5e9c0f0593ab3c058e282bfa". I then want to remove a requested day from the nested objects array. From the above query, I am receiving an array of dates and on each index of array the document is in this format:
[{
"_id" : ObjectId("5ea7f54b8b22480431f1a455"),
"day" : "1588186800",
"typesOfTicket" : [
{
"_id" : ObjectId("5ea7f54b8b22480431f1a456"),
"ticket" : "Adult Tickets",
"noTickets" : 40,
"price" : 50,
"ticketsLeft" : 40
},
{
"_id" : ObjectId("5ea7f54b8b22480431f1a457"),
"ticket" : "Children Tickets",
"noTickets" : 50,
"price" : 30,
"ticketsLeft" : 50
}
],
"event" : ObjectId("5e9c0f0593ab3c058e282bfa"),
"__v" : 0
},
{
"_id" : ObjectId("5ea7f5678b22480431f1a45f"),
"day" : "1588273200",
"typesOfTicket" : [
{
"_id" : ObjectId("5ea7f5678b22480431f1a460"),
"ticket" : "Male Tickets",
"noTickets" : 50,
"price" : 5,
"ticketsLeft" : 50
},
{
"_id" : ObjectId("5ea7f5678b22480431f1a461"),
"ticket" : "Female Tickets",
"noTickets" : 50,
"price" : 5,
"ticketsLeft" : 50
}
],
"event" : ObjectId("5e9c0f0593ab3c058e282bfa"),
"__v" : 0
}]
What i want is to find a way to remove the document in the nested typesOfTicket array, like lets say i want to remove the Object with id: typesOfTicketId. (e.g typesOfTicketId = "5ea7f5678b22480431f1a461"), the female ticket one by passing its ID.
I have already tried this query:
await EventDate.update({event: eventid}, {
$pull: {
typesOfTicket: {
_id: "typesOfTicketIDHERE"
}
}
});
But the above given query is only working if i am removing the first index of eventDays Array, like if i am deleting the ID: "5ea7f54b8b22480431f1a456", then this will work but if i am going for the id's on the second index like "Female tickets"/"5ea7f5678b22480431f1a461", then it is not working.
I found the solution to my problem, the above query did work correctly after just some adjustments
await EventDate.update({event: eventid}, {
$pull: {
typesOfTicket: {
_id: "typesOfTicketIDHERE"
}
}
}, { multi: true });
Just specifying the multi params to true will do the trick.
Here is the schema of my collection "profile"
{
_id : ObjectId("123"),
name : "Tommy",
defaultrates :
[
{_id : ObjectId("111"), rate : 35.0, raisedOn : "5/2/2009"},
{_id : ObjectId("222"), rate : 55.0, raisedOn : "5/3/2010"},
{_id : ObjectId("333"), rate : 65.0, raisedOn : "5/5/2010"}
]
}
I want to remove the first index of default rates ({_id : 111, rate : 35.0, raisedOn : "5/2/2009"}).
The result should be:
{
_id : ObjectId("123"),
name : "Tommy",
defaultrates :
[
{_id : ObjectId("222"), rate : 55.0, raisedOn : "5/3/2010"},
{_id : ObjectId("333"), rate : 65.0, raisedOn : "5/5/2010"}
]
}
I did this in the console:
db.profile.update({'_id: ObjectId("123")},{ $pull: { 'defaultrates':{'_id': "111"}}},{ multi: false })
But sadly, it didn't gave me the desired output.
Please help. What's the proper way of doing this?
I think you are mixing and matching quotes and double quotes indiscriminately. Try this:
db.profile.update({
"_id": ObjectId("123")
},
{
"$pull": {
"defaultrates": {
"_id": ObjectId("111")
}
}
},
false,
true
);
that false is multi. And true is upsert (if not available, insert one).
I am new to MongoDB and I am doing some exercises on it. In particular I got stuck on this exercise, of which I report here the question:
Given the following structure for document "Restaurant":
{
"_id" : ObjectId("5704adbc2eb7ebe23f582818"),
"address" : {
"building" : "1007",
"coord" : [
-73.856077,
40.848447
],
"street" : "Morris Park Ave",
"zipcode" : "10462"
},
"borough" : "Bronx",
"cuisine" : "Bakery",
"grades" : [
{
"date" : ISODate("2014-03-03T00:00:00Z"),
"grade" : "A",
"score" : 2
},
{
"date" : ISODate("2013-09-11T00:00:00Z"),
"grade" : "A",
"score" : 6
},
{
"date" : ISODate("2013-01-24T00:00:00Z"),
"grade" : "A",
"score" : 10
},
{
"date" : ISODate("2011-11-23T00:00:00Z"),
"grade" : "A",
"score" : 9
},
{
"date" : ISODate("2011-03-10T00:00:00Z"),
"grade" : "B",
"score" : 14
}
],
"name" : "Morris Park Bake Shop",
"restaurant_id" : "30075445"
}
Write a MongoDB query to find the restaurant Id, name and grades for those restaurants where 2nd element of grades array contains a grade of "A" and score 9 on an ISODate "2014-08-11T00:00:00Z".
I wrote this query:
db.restaurants.find(
{
'grades.1': {
'score': 'A',
'grade': 9,
'date' : ISODate("2014-08-11T00:00:00Z")
}
},
{
restaurant_id: 1,
name: 1,
grades: 1
});
which is not working.
The solution provided is the following:
db.restaurants.find(
{ "grades.1.date": ISODate("2014-08-11T00:00:00Z"),
"grades.1.grade":"A" ,
"grades.1.score" : 9
},
{"restaurant_id" : 1,"name":1,"grades":1}
);
My questions are:
is there a way to write the query avoiding to repeat the grades.1 part?
Why is my query wrong, given that grades.1 is a document object?
If it can help answering my question, I am using MongoDB shell version: 3.2.4
EDIT:
I found an answer to question 2 thanks to this question.
In particular I discovered that order matters. Indeed, if I perform the following query, I get a valid result:
db.restaurants.find({'grades.1': {'date': ISODate("2014-08-11T00:00:00Z"), 'grade':'A', score:9}}, {restaurant_id:1, name:1, grades:1})
Note that this query works only because all subdocument's "fields" are specified, and they are specified in the same order.
Not really. But perhaps an explanation of what you "can" do:
db.junk.find({
"grades": {
"$elemMatch": {
"date" : ISODate("2014-03-03T00:00:00Z"),
"grade" : "A",
"score" : 2
}
},
"$where": function() {
var grade = this.grades[0];
return (
grade.date.valueOf() == ISODate("2014-03-03T00:00:00Z").valueOf() &&
grade.grade === "A" &&
grade.score ==== 2
)
}
})
The $elemMatch allows you to shorten a little, but it is not the "nth" element of the array. In order to narrow that further you need to use the $where clause to inspect the "nth" array element to see if all values are a match.
db.junk.aggregate([
{ "$match": {
"grades": {
"$elemMatch": {
"date" : ISODate("2014-03-03T00:00:00Z"),
"grade" : "A",
"score" : 2
}
}
}},
{ "$redact": {
"$cond": {
"if": {
"$let": {
"vars": { "grade": { "$arrayElemAt": [ "$grades", 0 ] } },
"in": {
"$and": [
{ "$eq": [ "$grade.date", ISODate("2014-03-03T00:00:00Z") ] },
{ "$eq": [ "$grade.grade", "A" ] },
{ "$eq": [ "$grade.score", 2 ] }
]
}
}
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
You can do the same logic with $redact as well using .aggregate(). It runs a little quicker, but the basic truth should be clear by now.
So using "dot notation" to specify the "nth" position for each element within the array like you have already done is the most efficient and "brief" way to write this. You cannot make it shorter or better.
Your other attempt is looking for a "document" within "grades.1" that matches exactly the document condition you are providing. If for any reason those are not the only fields present, or if they are indeed in "different order" in the stored document, then such a query condition will not be a match.
I have the following Mongoose schema and model:
var deviceSchema = new Schema({
deviceId:String,
deviceName:String,
devicePlace:String,
socket : [{number: Number,name:String, state : Boolean, current: Number, image:Number,locked:Boolean,reserved:Boolean}]
});
I already have a device in my database with four sockets.
Here example!
This is original data.
{
"_id" : ObjectId("5626569006bc3da468bafe93"),
"deviceId" : "0013A20040B5769A",
"deviceName" : "device",
"devicePlace" : "place",
"__v" : 0,
"socket" : [
{
"_id" : ObjectId("5628bd83570be84e28879e2d"),
"number" : 0,
"name" : "name"
"state" : true,
"current" : 0
"image" : 0,
"locked" : false,
"reserved" : false,
}, ...
]
}
and I received data from client for update.
{
"_id" : ObjectId("5626569006bc3da468bafe93"),
"deviceId" : "0013A20040B5769A",
"__v" : 0,
"socket" : [
{
"_id" : ObjectId("5628bd83570be84e28879e2d"),
"number" : 0,
"name" : "new name!!!!!"
"state" : true,
"current" : 0
}, ...
]
}
Now I'm trying to update a specific socket's name in the database with the following command:
device.update({deviceId: newData.deviceId, "socket.number": newData.number}, {$set: {"socket.$.name": newData.name}})
newData is object that extracted from socket array in received data.
I want to just update first socket's name.
or if possible, I want to update every socket's name as received socket array.
But this does not seem to be working, but I get no error. Can someone pin point what I'm doing wrong?