Hi I have mongodb query like this .
.aggregate(
[
{ $match : { comment_box : "somdata" } },
{ $project : {
comment : 1,
created_at: 1,
current_date: "$replies.created_at",
},
dateDifference: { $subtract: [ new Date(), "$created_at"] }
}},
]
)
Imagine that I want to get created_at value from replies array in current date field. but this query returns
current_date: [
"2016-03-08T13:48:27.882Z",
"2016-03-08T14:26:22.194Z"
]
instead of current created_at value of each element from this array
I have tried many ways but got errors
current_date: "$replies.0.created_at",
current_date: "$replies.$.created_at",
current_date: "$$replies.created_at",
and etc
please help me to retrieve data like this
current_date:"2016-03-08T13:48:27.882Z",
I’m assuming you want the latest comment date. In that case, you can just take the $max:
current_date: { $max: '$replies.created_at' }
Demo:
> db.comments.insert({_id: 0, replies: [{created_at: new Date('2017-04-03')}, {created_at: new Date('2017-02-03')} ]})
WriteResult({ "nInserted" : 1 })
> db.comments.insert({_id: 1, replies: []})
WriteResult({ "nInserted" : 1 })
> db.comments.aggregate([{$project: {current_date: {$max: '$replies.created_at'}}}])
{ "_id" : 0, "current_date" : ISODate("2017-04-03T00:00:00Z") }
{ "_id" : 1, "current_date" : null }
Notice how the document with an empty replies array gets null.
Related
I have a Mongoose schema which is like this:
const mySchema = new mongoose.Schema(
{
_id: String,
coin: String,
closeTime: Number,
volume: Number,
}
I have a bunch of different coins. Is it possible to get the latest document for each unique coin I have based on the closeTime?
Help would be much appreciated! Thanks.
You can use aggregation to sort by latest/newest closeTime, group by coin then getting the first document of that group:
mySchema.aggregate([
{ $sort: { closeTime: -1 } },
{ $group: { _id: "$coin", latest: { $first: "$$ROOT" } } }
])
This is sorting with numeric closeTime in descending order, getting the first/latest document and putting its data into a property called latest. This should create results like:
[{
"_id" : "2",
"latest" : {
"_id" : ObjectId("6149f106742bb30e2529c453"),
"coin" : "foo",
"closeTime" : 5,
"volume" : 1
}
}
{
"_id" : "1",
"latest" : {
"_id" : ObjectId("6149f111742bb30e2529c45f"),
"coin" : "bar",
"closeTime" : 4,
"volume" : 1
}
}]
You can take this one step further with other aggregation stages to extract/project the underlying coin document.
this is my first time asking in StackOverflow and I hope I can explain what I'm aiming for.
I've got documents that look like this:
"_id" : ObjectId("5fd76b67a7e0fa652a297a9f"),
"type" : "play",
"session" : "5b0b5d57-c3ca-415f-8ef6-49bbd5805a23",
"episode" : 1,
"show" : 1,
"user" : 1,
"platform" : "spotify",
"currentTime" : 0,
"date" : ISODate("2020-12-14T13:40:51.906Z"),
"__v" : 0
}
I'd like to fetch for a show and group them by episode. I've got this far with my aggregattion:
const filter = { user, show, type: { $regex: /^(play|stop|close)$/ } }
const requiredFields = { "episode": 1, "session": 1, "date": 1, "currentTime": 1 }
// Get sessions grouped by episode
const it0 = {
_id: '$episode',
session:
{$addToSet:
{_id: "$session",
date:{$dateToString: { format: "%Y-%m-%d", date: "$date" }},
averageOfSession: {$cond: [ { $gte: [ "$currentTime", 0.1 ] }, "$currentTime", null ] }
},
},
count: { $sum: 1 }
}
// Filter unique sessions by session id and add them to a sessions field
const reduceSessions = {$addFields:
{sessions: {$reduce: {input: "$session",initialValue: [],in:
{$concatArrays: ["$$value",{$cond: [{$in: ["$$this._id","$$value._id"]},[],["$$this"]]}]}
}}}}
const projection = { $project: { _id: 0, episode: "$_id", plays: {$size: '$sessions'}, dropoff: {$avg: "$sessions.averageOfSession"}, sessions: '$session.date', events: "$count" } }
const arr = await Play.aggregate([
{ $match: filter }, {$project: requiredFields}, {$group: it0}, reduceSessions,
projection,{ $sort : { _id : 1 } }
])
and this is what my result looks like so far:
{
"episode": 5,
"plays": 4,
"dropoff": 3737.25,
"sessions": [
"2020-11-15",
"2020-11-15",
"2020-11-16",
"2020-11-15"
],
"events": 4
}...
What I'd like is for the 'sessions' array to be an object with one key for each distinct date which would contain the count, so something like this:
{
"episode": 5,
"plays": 4,
"dropoff": 3737.25,
"sessions": {
"2020-11-15": 3,
"2020-11-16": 1
},
"events": 4
}...
Hope that makes sense, thank you!!
You can first map sessions into key-value pairs. Then $group them to add up the sum. Then use $arrayToObject to convert to the format you want.
This Mongo playground is referencing this example.
Below is the sample document of a collection, say "CollectionA"
{
"_id" : ObjectId("5ec3f19225701c4f7ab11a5f"),
"workshop" : ObjectId("5ebd37a3d33055331eb4730f"),
"participant" : ObjectId("5ebd382dd33055331eb47310"),
"status" : "analyzed",
"createdBy" : ObjectId("5eb7aa24d33055331eb4728c"),
"updatedBy" : ObjectId("5eb7aa24d33055331eb4728c"),
"results" : [
{
"analyze_by" : {
"user_name" : "m",
"user_id" : "5eb7aa24d33055331eb4728c"
},
"category_list" : [
"Communication",
"Controlling",
"Leading",
"Organizing",
"Planning",
"Staffing"
],
"analyzed_date" : ISODate("2020-05-19T14:48:49.993Z"),
}
],
"summary" : [],
"isDeleted" : false,
"isActive" : true,
"updatedDate" : ISODate("2020-05-19T14:48:50.827Z"),
"createdDate" : ISODate("2020-05-19T14:47:46.374Z"),
"__v" : 0
}
I need to query all the documents to get the "results" array length and return a sum of all document's "results" length.
For example,
document 1 has "results" length - 5
document 2 has "results" length - 6
then output should be 11.
Can we write a query, instead of getting all, iterating and the adding the results length??
If I had understand clearly you would like to project the length of the result attribute.
So you should check the $size operator would work for you.
https://docs.mongodb.com/manual/reference/operator/aggregation/size/
You can use $group and $sum to calculate the total size of a field which contains the size of your results array. To create the field, You can use $size in $addFields to calculate the size of results in each document and put it the field. As below:
db.getCollection('your_collection').aggregate([
{
$addFields: {
result_length: { $size: "$results"}
}
},
{
$group: {
_id: '',
total_result_length: { $sum: '$result_length' }
}
}
])
You use an aggregation grouping query with $sum and $size aggregation operators to get the total sum of array elements size for all documents in the collection.
db.collection.aggregate( [
{
$group: {
_id: null,
total_count: { $sum: { $size: "$results" } }
}
}
] )
Aggregation using Mongoose's Model.aggregate():
SomeModel.aggregate([
{
$group: {
_id: null,
total_count: { $sum: { $size: "$results" } }
}
}
]).
then(function (result) {
console.log(result);
});
Code created in Mongoose to update a subdocument was not working. So I tried to update the subdocument within the Mongo Shell.
This is the document (location) and subdocument (review):
{
"_id" : ObjectId("56d8c73314fbc7e702cfb8c4"),
"name" : "Costly",
"address" : "150, Super Street",
"coords" : [
-0.9630884,
51.451041
],
"reviews" : [
{
"author" : "kyle riggen1",
"_id" : ObjectId("56d8de74cc7f953efd8455d9"),
"rating" : 4,
"timestamp" : ISODate("2015-06-01T06:00:00Z"),
"reviewText" : "will the ID work?"
}
],
"rating" : 0,
"__v" : 2
}
Here are some of my attempts at updating the subdocument:
This question gave this format:
update({
_id: "56d8c73314fbc7e702cfb8c4",
"reviews._id": ObjectId("56d8de74cc7f953efd8455d9")
},{
$set: {"reviews.$.rating": 1}
}, false, true
);
This returned an error of "update is not defined" as shown:
2016-03-03T22:52:44.445-0700 E QUERY [thread1] ReferenceError: update is not defined :
#(shell):1:1
Which I think is because the command did not start with db.locations.update()
MongoDB documentation used this format:
db.locations.update(
{
_id: "56d8c73314fbc7e702cfb8c4",
review: { $elemMatch: { author: "kyle riggen1" } }
},
{ $set: { "location.$.rating" : 1 } }
)
This returns a valid update but the update didn't actually happen as shown:
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })
This question used this format:
db.locations.update({
_id: "56d8c73314fbc7e702cfb8c4",
'review.author': 'kyle riggen1'
},
{ $set: { 'review.$.rating': 1 }}
)
This returns the same as the MongoDB documentation as shown here:
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })
So these queries I guess are working but my data is not getting updated. Would my data be indexed wrong perhaps? The actual location is able to be updated even through a Mongoose API.
You can do it By $push Or $addToSet.
db.col.update(
{ name: 'reviews', 'list.id': 2 },
{$push: {'list.$.items': {id: 5, name: 'item5'}}}
)
See the reference from mongodb Manual
https://docs.mongodb.org/manual/reference/operator/update/push/
Please know db.collection.update( criteria, objNew, upsert, multi )
criteria: match condition
objNew: update content
upsert: true or false
true : if not existed, insert it
false : if not existed, don't insert
multi: true or false
true : update all matched documents
false : only update the first matched document
I have a collection db.activities, each item of which has a dueDate. I need to present data in a following format, which basically a list of activities which are due today and this week:
{
"today": [
{ _id: 1, name: "activity #1" ... },
{ _id: 2, name: "activity #2" ... }
],
"thisWeek": [
{ _id: 3, name: "activity #3" ... }
]
}
I managed to accomplish this by simply querying for the last week's activities as a flat list and then grouping them with javascript on the client, but I suspect this is a very dirty solution and would like to do this on server.
look up mongo aggregation pipeline.
your aggregation has a match by date, group by date and a maybe a sort/order stage also by date.
lacking the data scheme it will be along the lines of
db.collection.aggregate([{ $match: {"duedate": { "$gte" : start_dt, "$lte" : end_dt} } ,
{ $group: {_id: "$duedate", recordid : "$_id" , name: "$name" },
{"$sort" : {"_id" : 1} } ] );
if you want 'all' records remove the $match or use { $match: {} } as one does with find.
in my opinion, you cannot aggregate both by day and week within one command. the weekly one may be achieved by projecting duedate using mongos $dayOfWeek. along the lines of
db.collection.aggregate([
{ $match: {"duedate": { "$gte" : start_dt, "$lte" : end_dt} } ,
{ $project : { dayOfWeek: { $dayOfWeek: "$duedate" } },
{ $group: {_id: "$dayOfWeek", recordid : "$_id" , name: "$name" },
{"$sort" : {"_id" : 1} } ] );
check out http://docs.mongodb.org/manual/reference/operator/aggregation/dayOfWeek/