A mongo DB query with a MAX(DATE) - mongodb

Hello I have a BD with many fields where an user can enter many times, I need to create a query where I can Group by user and bring me the last entry date in the system, but other additional data such as previous and the ID of the transaction, the date is createdAT, it brings me the date but not the last one ... here the code:
db.getCollection("usersos").aggregate(
[
{
"$group" : {
"_id" : {
"_id" : "$_id",
"user" : "$user",
"previo" : "$previo"
},
"MAX(createdAt)" : {
"$max" : "$createdAt"
}
}
},
{
"$project" : {
"user" : "$_id.user",
"MAX(createdAt)" : "$MAX(createdAt)",
"_id" : "$_id._id",
"previo" : "$_id.previo"
}
}
]
);
Im staring in nosql, some help thank.....and excuseme the mstake....

Grouping by $_id will mean that every input document is a separate group, i.e. no grouping will really happen.
You could try pre-sorting by createdAt, which might be helped by an index on that field, then the group can select $first to get the first entry for each field that you care about.
db.usersos.aggregate([
{$sort: {createdAt: -1}},
{$group: {
_id:"$user",
docId: {$first: "$_id"},
previo: {$first: "$previo"},
createdAt: {$first: "$createdAt"}
}},
{ $project: {
user: "$_id",
_id: "$docId",
previo: 1,
createdAt: 1
}}
])

Related

Mongoldb aggregation check how many times a field value in an array comes up?

I have a collection of documents that look like this
{
_id : 21353456,
product : "xy",
text : "asdf",
reviews : [
{
username : "User1",
userID: 12
text : "hi",
},
{
username : "User2",
userID: 123
text : "hi1",
}
]
}
users can make multiple reviews on different products, I want to retrieve all the users that have made at least 3 reviews. I want to see the number of reviews, the reviewer name and id in alphabetic order.
I have tried this code but it doesn't work
db.reviews.aggregate([{
$group:{
"_id": "$userID", "$userName","$text"
"numRev":{$numRev:{}}}}, {$match:{"numRev":{$gte: 3}}}, {$sort: {"reviewerName" : 1}}])
Maybe something like this:
db.collection.aggregate([
{
$unwind: "$reviews"
},
{
$group: {
_id: "$reviews.username",
userID: {
$last: "$reviews.userID"
},
reviewsNum: {
$sum: 1
}
}
},
{
$match: {
reviewsNum: {
$gte: 3
}
}
},
{
$sort: {
_id: 1
}
}
])
Explained:
Unwind the reviews array
Group by username so you get the count of reviews per user
Match only those reviews >=3
Sort by _id-> the username.
playground

Mongodb find duplicates where second column matches

I want to find duplicate documents in my mongodb database , and i have also achieved a portion of it , lets say my document is something like this
{
"_id" : ObjectId("5900b01b2ce12a2383328e61"),
"Bank Name" : "Seaway Bank and Trust Company",
"City" : "Chicago",
"ST" : "IL",
"CERT" : 19328,
"Acquiring Institution" : "State Bank of Texas",
"Closing Date" : "27-Jan-17",
"Updated Date" : "17-Feb-17"
}
and i have written query like this :
db.list.aggregate([
{$group: {
_id: {CERT: "$CERT"},
uniqueIds: {$addToSet: "$_id"},
count: {$sum: 1}
}
},
{$match: {
count: {"$gt": 1}
}
},
{$sort: {
count: -1
}
}
]);
so this gives me ids of all the documents where CERT is repeating in more than one document which is correct , but in addition to this , i want to add and where ST not equals to IL. how can i do that .
Please Help !
You can just add another $match with ST not equals to IL, before executing the $group, which will ignore the transactions with "ST" == "IL":
Final Query:
db.list.aggregate([
{
$match : {
"ST" : {$ne : "IL"}
}
},
{
$group: {
_id: {CERT: "$CERT"},
uniqueIds: {$addToSet: "$_id"},
count: {$sum : 1}
}
},
{
$match: {
count: {"$gt": 1}
}
},
{
$sort: {
count: -1
}
}
]);
Hope this Helps!
You can use this
db.list.aggregate([
{$group: {
_id: {CERT: "$CERT",ST:{$ne:"IL"}},
uniqueIds: {$addToSet: "$_id"},
count: {$sum: 1}
}
},
{$match: {
count: {"$gt": 1}
}
},
{$sort: {
count: -1
}
}
]);
Let me know if it did not worked or you need some more help

Find number of duplicates documents

I had a bug on my code while developing that created some duplicated users on my MongoDB.
Collection example:
"_id" : ObjectId("5abb9d72b884fb00389efeef"),
"user" : ObjectId("5abb9d72b884fb00389efee5"),
"displayName" : "test",
"fullName" : "test test test",
"email" : "test#mail.com",
"phoneNumber" : "99999999999",
"createdAt" : ISODate("2016-05-18T13:49:38.533Z")
I was able to find the duplicated users with this query:
db.users.aggregate([{$group: {_id: "$user", "Total": {$sum: 1}}}, {
$match: { "Total": {$gt: 1}}}])
And count them with this one:
db.users.aggregate([{$group: {_id: "$user", "Total": {$sum: 1}}}, {
$match: { "Total": {$gt: 1}}}, { $count: "Total"}])
I want to know how many users I'll need to delete, but the second query only returns me the total of unique users affected.
How can I get a sum of duplicated users? Or a sum of "Total".
Expected result:
{ "Total" : **** }
Well, you can do this with the following pipeline
[
{ $group: {
_id: null,
uniqueValues: { $addToSet: "$user" },
count: { $sum: 1 }
}},
{ $project: {
total: { $subtract: [ "$count", { $size: "$uniqueValues" } ] }
}}
]
Don't have your data set, so didnt test this in my local. Try this query:
db.users.aggregate([
{$group: {_id: "$user", Total: {$sum: 1}}}, //group by user and count each.
{$addFields: {Total: {$subtract:["$Total",1]}}}, // you need duplicate count, so forget first instance of it.
{$group:{_id:null, Total: {$sum:"$Total"}}}, // your _id is unique, perform a sum out of it
{$project:{_id:0, Total:1}} // at the end the result is total number of 'duplicate' users.
])

Combine 2 separate results mongo db

I'm working on an eCommerce based website using MongoDb.
In my db collection I have 2 type of documents
Company details Item
{ doc_type : 'company',
name : 'Acer',
type : 'Laptops',
helpline : '1800-200-000'
}
Item Details
{doc_type : "item",
item_id : 1001,
price : 2000,
discount : 20}
Now in product page i need to get data from both document.
so, first i run
db.collection.find({doc_type:'item', item_id : 1001 });
to show product data and then
db.collection.find({doc_type:'company', name: "Acer"});
to get company data.
Is their any way to reduce these 2 calls to one and get data in single result set.
like
{
company : { //company data},
item : { //item details }
}
To achieve the sample output that you have shared, along with the $match and $group stages, I have added a $project stage.
db.col.aggregate([
{
$match:
{
$or: [
{doc_type:'item', item_id : 1001 },
{doc_type:'company', name: 'Acer'}
]
}
},
{
$group:
{
_id: null,
"company_name": {$max: "$name"},
"company_type": {$max: "$type"},
"company_helpline": {$max: "$helpline"},
"item_price": {$max: "$price"},
"item_discount": {$max: "$discount"}
}
},
{
$project:
{
_id: 0,
'company' : {
'name': '$company_name',
'type': '$company_type',
'helpline': '$company_helpline',
},
'item' : {
'price': '$item_price',
'discount': '$item_discount'
}
}
}
]).pretty()
Output :
{
"company" : {
"name" : "Acer",
"type" : "Laptops",
"helpline" : "1800-200-000"
},
"item" : {
"price" : 2000,
"discount" : 20
}
}
You can achieve this using aggregation using a $match and a $group stage.
The query would be :
db.it.aggregate([
{$match:
{$or: [
{doc_type:'item', item_id : 1001 },
{doc_type:'company', name: "Acer"}
]
}
},
{$group:
{_id: null,
"compagny_name": {$max: "$name"},
"compagny_type": {$max: "$type"},
"compagny_helpline": {$max: "$helpline"},
"item_price": {$max: "$price"},
"item_discount": {$max: "$discount"}
}
}] )
this output :
{
"_id":null,
"compagny_name":"Acer",
"compagny_type":"Laptops",
"compagny_helpline":"1800-200-000",
"item_price":2000,
"item_discount":20
}

Use of $COND and $EQ with a array of objects

I'm hoping that someone might be able to answer whether what I'm trying to accomplish below can be done with the MongoDB Aggregation Framework.
I have a user data structure that resembles the following with close to 1 million documents.
{
"firstName" : "John",
"lastName" : "Doe",
"state" : "NJ",
"email" : "JOHNDOE#XYZ.COM"
"source" : [
{
"type" : "SOURCE-A",
"data" : {
"info" : "abc",
"info2" : "xyz"
}
},
{
"type" : "SOURCE-B",
"data" : {
"info3" : "abc"
}
}
]
}
For the purposes of feeding data to another system, I need to generate a flat file structure with limited information from the previous dataset. The columns need to represent:
firstname, lastname, email, is_source-a, is_source-b
The part that I'm having difficulty with is the conditional code that attempts to populate "is_source-a" and "is_source-b". I have tried to use the following aggregation query, but can't figure out how to get it working since the $EQ operator used along with $COND doesn't seem to evaluate data inside of an array (always false).
db.collection.aggregate([
{
$project : {
_id : 0,
firstName : 1,
lastName: 1,
"is_source-a" : {
$cond : [
{ $eq: [ "$source.type", "source-a" ] },
1,
0
]
},
"is_source-b" : {
$cond : [
{ $eq: [ "$source.type", "source-b" ] },
1,
0
]
}
}
}
]);
I could $UNWIND the array first, but then I wind up with a multiple records for each user document and don't understand how to consolidate them back.
Is there something that I'm missing with how to use $EQ (or some other operator) along with $COND when dealing with arrays of objects?
You're definitely on the right track, and using $unwind can get you there if you follow it up with a $group to put things back together:
db.collection.aggregate([
{$unwind: '$source'},
{$project: {
_id: 1,
firstName: 1,
lastName: 1,
email: 1,
'is_source-a': {$eq: ['$source.type', 'SOURCE-A']},
'is_source-b': {$eq: ['$source.type', 'SOURCE-B']}
}},
// group the docs that were duplicated in the $unwind back together by _id,
// taking the values for most fields from the $first occurrence of the _id,
// but the $max of the is_source fields so that if its true in any of the
// docs for that _id it will be true in the output for that _id.
{$group: {
_id: '$_id',
firstName: {$first: '$firstName'},
lastName: {$first: '$lastName'},
email: {$first: '$email'},
'is_source-a': {$max: '$is_source-a'},
'is_source-b': {$max: '$is_source-b'}
}},
// project again to remove _id
{$project: {
_id: 0,
firstName: 1,
lastName: 1,
email: 1,
'is_source-a': '$is_source-a',
'is_source-b': '$is_source-b'
}}
])
If you do not want to $unwind and $group this can also be achieved with $cond and $in.
I found this originally here: https://www.mongodb.com/community/forums/t/cond-inside-an-array-is-not-working/156468
I was a bit surprised this works, but as the mongo docs state:
$in
has the following operator expression syntax:
{ $in: [ <expression>, <array expression> ] }
For the original question (I'm sure you're still waiting on this 8 years later), it could be done like this:
db.collection.aggregate([
{
$project : {
_id : 0,
firstName : 1,
lastName: 1,
"is_source-a" : {
$cond : [
{ $in: [ "source-a", "$source.type" ] },
1,
0
]
},
"is_source-b" : {
$cond : [
{ $in: [ "source-b", "$source.type" ] },
1,
0
]
}
}
}
]);