I have a collection myCollection,
ID DateTime myID Cost Flag
1 '2016-07-01T00:00:00' 2048 1 'O'
2 '2016-07-02T00:00:00' 2049 2 'O'
if I write sql query for it
"select DateTime, myID,Flag, min(Cost) from myCollection group by DateTime, myID"
it will display all the fields in data e.g
DateTime, myID,Flag, min(Cost)
but in mongo aggregation framework I can group like
db.myCollection.aggregate([
{
$group: {
_id: {
DateTime: '$DateTime',
myID: '$myID'
},
minCost: { $min: '$Cost' }
}
}
])
which will return me
DateTime, myID, min(Cost)
but I need "Flag" field also in single query. I tried out $Push but it works only for an array.
In SQL Server, the query
select DateTime, myID,Flag, min(Cost) from myCollection group by DateTime, myID
is invalid in the select list because the column Flag is not contained in either an aggregate function or the GROUP BY clause.
In MongoDB, to be able to include the field Flag in the aggregate query, you must apply an accumulator operator on the field and in this case you may either use the $first or $last accumulator operators to return the field value within the aggregation.
db.myCollection.aggregate([
{
"$group": {
"_id": {
"DateTime": '$DateTime',
"myID": '$myID'
},
"minCost": { "$min": '$Cost' },
"Flag": { "$first": '$Flag' }
}
}
])
in the above, the $first accumulator operator applied on the Flag field will return a Flag value from the first document for each group. Order is only defined if the documents are in a defined order.
Related
I have a mongo collection called items. I want to find the 10 highest priced items out of the active ones. My problem is the price is a string. So my question is how can I cast price as numeric and then sort the active items in descending order over price?
My current attempt gives me the highest price in alphanumeric order, i.e. 999. But I have items that are way pricier.
db.getCollection('items').find({"status": "active"})
.sort({"packet.price":-1})
.limit(10)
I tried:
sort({{$toInt:"packet.price"}:-1}),
sort({NumberInt("packet.price"):-1})
but no luck.
It is not possible with find method, you can use the aggregation framework,
$match to match your query condition
$addFields to change type of price field using $toInt operator
$sort by price in descending order
$limit 10 documents
db.getCollection('items').aggregate([
{ "$match": { "status": "active" }, },
{ "$addFields": { "$toInt": "$packet.price" } },
{ "$sort": { "packet.price": -1 } },
{ "$limit": 10 }
])
I am having a record set like below :
I need to write a query where foreach datatype of every parent I show the data type with highest date i.e
So far I am able to create two groups one on parent id & other on data type but i am unable to understand how to get record with max date.
Below is my query :
db.getCollection('Maintenance').aggregate( [{ $group :
{ _id :{ parentName: "$ParentID" , maintainancename : "$DataType" }}},
{ $group : {
_id : "$_id.parentName",
maintainancename: {
$push: {
term:"$_id.DataType"
}
}
}
}] )
You don't have to $group twice, try below aggregation query :
db.collection.aggregate([
/** group on two fields `ParentID` & `Datatype`,
* which will leave docs with unique `ParentID + Datatype`
* & use `$max` to get max value on `Date` field in unique set of docs */
{
$group: {
_id: {
parentName: "$ParentID",
maintainancename: "$Datatype"
},
"Date": { $max: "$Date" }
}
}
])
Test : mongoplayground
Note : After group stage you can use $project or $addFieldsstages to transform fields the way you want.
Let's say my mongo document looks like this:
{
_id: "some _id",
name: "some name",
type: "A" | "B" | "C" | or it may be null
}
When I call db.getCollection('mycollection').find().sort({ type: -1 }) I'm getting documents with type: null first because the data is sorted by canonical type where null has much lower canonical value than that of number/string
Is there a way to form a query, so that null values would appear last?
I have found this question How can I sort into that nulls are last ordered in mongodb? but there it's suggested to use aggregation and add "fake" values which does not seem good to me.
Using aggregation may work if forming a facet with sorted documents where sorting criteria is not null and documents where it is null and then concatinating both arrays, but that can get complicated when there're more than one sorting criteria.
You can use $type operator to get a type of field (null or string) and then $sort by field type plus then by your field, try:
db.col.aggregate([
{ $addFields: { fieldType: { $type: "$type" } } },
{ $sort: { fieldType: -1, type: 1 } },
{ $project: { "fieldType": 0 } }
])
We have a rudimentary versioning system in a collection that uses a field (pageId) as a root key. Subsequent versions of this page have the same pageId. This allows us to very easily find all versions of a single page.
How do I go about running a query that returns only the lastModified document for each distinct pageId.
In psuedo-code you could say:
For each distinct pageId
sort documents based on lastModified descending
and return only the first document
You can use the aggregation pipelines for that.
$sort - Sorts all input documents and returns them to the pipeline in sorted order.
$group - Groups documents by some specified expression and outputs to the next stage a document for each distinct grouping.
$first - Returns the value that results from applying an expression to the first document in a group of documents that share the same group by key.
Example:
db.getCollection('t01').aggregate([
{
$sort: {'lastModified': -1}
},
{
$group: {
_id: "$pageId",
element1: { $first: "$element1" },
element2: { $first: "$element2" },
elementN: { $first: "$elementN" },
}
}
]);
How do I structure my MongooseJS/MongoDB query to get total duplicates/occurrences of a particular field value? Aka: The total documents with custID of some value for all custIDs
I can do this manually in command line:
db.tapwiser.find({"custID" : "12345"}, {}, {}).count();
Outputs: 1
db.tapwiser.find({"custID" : "6789"}, {}, {}).count();
Outputs: 4
I found this resource:
How to sum distinct values of a field in a MongoDB collection (utilizing mongoose)
But it requires that I specify the unique fields I want to sum.
In this case, I want to loop through all documents, sum the occurrences of each.
All you need to do is $group your documents by custID and use the $sum accumulator operator to return "count" for each group.
db.tapwiser.aggregate(
[
{ "$group": { "_id": "$custID", "count": { "$sum": 1 } } }
], function(err, results) {
// Do something with the results
}
)