Mongo Aggregation - javascript

I have following documents in my collection
{
"_id": ObjectId("54490b8104f7142f22ecc97f"),
"title": "Sample1",
"slug": "samplenews",
"cat": "sports",
"desc": "sampletextsampletext",
"published_date": ISODate("2014-10-23T14:06:57.0Z"),
} {
"_id": ObjectId("54490b8104f7142f22ecc97f"),
"title": "Sample2",
"slug": "samplenews2",
"category": "entertaintment",
"desc": "sampletextsampletext",
"published_date": ISODate("2014-10-22T14:06:57.0Z"),
} {
"_id": ObjectId("54490b8104f7142f22ecc97f"),
"title": "Sample3",
"slug": "samplenews3",
"category": "entertaintment",
"desc": "sampletextsampletext",
"published_date": ISODate("2014-9-22T14:06:57.0Z"),
} {
"_id": ObjectId("54490b8104f7142f22ecc97f"),
"title": "Sample4",
"slug": "samplenews4",
"category": "other",
"desc": "sampletextsampletext",
"published_date": ISODate("2014-10-22T14:06:57.0Z"),
}
I need one query to get top 5 latest news from each category.any suggestions?

Assuming you have the latest version of mongodb installed, one way of doing it is:
Sort the records based on the published_date in descending order.
group the records based on their category. For each group, collect all the records together in an array.
In the javascript/client side code, slice the top 5 records, of each group(category).
The $slice is not available in the server side $project aggregation pipeline operator, which holds us from performing the operation on the server side.
var result = db.collection.aggregate(
[
{$sort:{"published_date":-1}},
{$group:{"_id":"$category","values":{$push:"$$ROOT"}}}
]
).map(function(doc){
return {"category":doc._id,"records":doc.values.slice(0,5)};
});
The result variable will now be an array of documents. Each document representing each category and in turn having an array of top 5 records.

You can sort and then limit your request.
$top_five_other = iterator_to_array($db->find(array('category'=>'other')->sort(array('published_date'=>-1))->limit(5));

you can try aggregate query
1-db.collection.aggregate({ $group : { _id : { category:"$category"}, total : { $sum : 1 }}},{$sort:{_id:1}})
OR
db.collection.aggregate({ $group : { _id : { category:"$category"}, total : { $sum : 1 }}},{$sort:{_id:1}})..forEach( function(myDoc) {
print(myDoc._id.category);
})

Related

Employees in companies - displaying JSON data in html table

I have json data like this :
{
"people": [
{
"id": "1",
"company": "Blitz",
"fullName": "Chad anderson"
},
{
"id": "2",
"company": "NFZ",
"fullName": "surge bash"
},
{
"id": "3",
"company": "Ultimate Chad Company LLC",
"fullName": "George"
},
{
"id": "4",
"company": "Blitz",
"fullName": "Chad kuton"
},
{
"id": "5",
"company": "NFZ",
"fullName": "piguła"
},
]);
currently I have code like this:
function appendData(data) {
let tblBody = document.getElementById('tableWithContent');
let outPut = '';
data.sort((a,b) => a.company.localeCompare(b.company));
for(let person of data){
outPut += `<tr>
<td></td>
<td>${person.fullName}</td>
<td>${person.company}</td>
</tr>`;
}
tblBody.innerHTML = outPut;
};
I would like to display it in a way that :
Creates html table populated with companies and names of employess, within that company. In a way that if both workers have the same company , they are just displayed within that one company.
However, the code displays , and it displays workers in one column, and companies in another.
I would like to know if there is a neat way to use for example. reduce() method to that.
So when I fetch this data to html it displays all of the people from one company , then all of the people from another company (without displaying the companies of employees each time - if they are from the same company).

MongoDB aggregate function is not returning the value of collection joined using JavaScript

I needed assistance in order to work out why the aggregate function is not responding the way I'd expect it to respond. This is a RESTful API service I've designed in which I am trying to connect collections with each other. Please note the following:
Collection: Season
{
"_id": {
"$oid": "5c0fc60bfb6fc04dd6ea4e9a"
},
"Season": "1",
"TotalEpisode": "15",
"Name": null,
"Description": "First season with no name for this drama",
"PlayID": "5c0fc4aafb6fc04dd6ea4d81"
}
Collection: Play
{
"_id": {
"$oid": "5c0fc4aafb6fc04dd6ea4d81"
},
"Name": "It was the first time",
"Description": "One of the best action heros in the entertainment industry until this day",
"ReleaseDate": "24/12/2010",
"EndingDate": "12/08/2012",
"Category": "Drama"
}
My implemented code in JavaScript
function getTestLookUp(db, collectionName, response, secondCollectionName){
console.log('First collection name: ' + collectionName + '\n' + 'Second collection name: ' + secondCollectionName);
db.collection(collectionName).aggregate([
{
$lookup:
{
from: secondCollectionName,
localField: 'PlayID',
foreignField: '_id',
as: 'requestedDetails'
}
}
]).toArray((err, res) => {
if(err){
console.log(err);
} else {
console.log(res);
response.status(200).json({
'Items': res
});
}
});
}
The response
{
"Items": [
{
"_id": "5c0fc60bfb6fc04dd6ea4e9a",
"Season": "1",
"TotalEpisode": "15",
"Name": null,
"Description": "First season with no name for this drama",
"PlayID": "5c0fc4aafb6fc04dd6ea4d81",
"requestedDetails": []
}
]
}
The things I've checked so far: the collection names are accurate, the ID is also accurate as I can search it up on the MLabs search feature. I don't understand as to why this is returning a empty 'requestedDetails' as I hoped it would return the item from the Play collection.
In addition to this, I would also appreciate if someone can point out how I can join multiple collections instead of 2.
I welcome any questions regarding this problem.
While still researching for this issue, I accidentally came across a another problem in which someone wrote a comment stating that "you might be comparing a String with ObjectID". This was the cause for this error as I obtain a String variable in return from the database and I am comparing the String variable with the _id which is expecting to see a ObjectID variable to complete the query. Therefore, meaning that my query/lookup is never matching these two variables.
The only way tackle this issue is to do a conversion (string to ObjectID) and then compare the values. However, since I'm using the version of ^3.1.10 of MongoDB, this functionality is not possible. Will need to update the version to 4.0 to be able to implement this functionality.
In order to rectify this issue, I managed to surround the foreign ID within $iod tags.
Before
{
"_id": {
"$oid": "5c0fc60bfb6fc04dd6ea4e9a"
},
"Season": "1",
"TotalEpisode": "15",
"Name": null,
"Description": "First season with no name for this drama",
"PlayID": "5c0fc4aafb6fc04dd6ea4d81"
}
After
{
"_id": {
"$oid": "5c0fc60bfb6fc04dd6ea4e9a"
},
"Season": "1",
"TotalEpisode": "15",
"Name": null,
"Description": "First season with no name for this drama",
"PlayID": {
"$oid": "5c0fc4aafb6fc04dd6ea4d81"
}
}
Response
{
"Items": [
{
"_id": "5c0fc60bfb6fc04dd6ea4e9a",
"Season": "1",
"TotalEpisode": "15",
"Name": null,
"Description": "First season with no name for this drama",
"PlayID": "5c0fc4aafb6fc04dd6ea4d81",
"Details": [
{
"_id": "5c0fc4aafb6fc04dd6ea4d81",
"Name": "It was the first time",
"Description": "One of the best action heros in the entertainment industry until this day",
"ReleaseDate": "24/12/2010",
"EndingDate": "12/08/2012",
"Category": "Drama"
}
]
}
]
}

How to loop through array of objects in Node/Express and check if a match exists in MongoDB database?

I am building a web app with the MEAN stack and Yelp API that returns an array of objects, where each object is a local business. I work with this data in the front-end, but before I send a response I want to check if a particular object exists in the MongoDB database and I am struggling with how to do that.
Here is an object that is returned from the API:
[
{
"name": "Arendsnest",
"url": "https://www.yelp.com/biz/arendsnest-amsterdam-2?adjust_creative=ycRBsh7KEkNFq3wJvKoL6Q&utm_campaign=yelp_api&utm_medium=api_v2_search&utm_source=ycRBsh7KEkNFq3wJvKoL6Q",
"snippet_text": "The reigning Lord of Amsterdam beer bars. Popular and seats go fast...come early. Ask for the massive all-Dutch beer list and prepare to have your...",
"image_url": "https://s3-media2.fl.yelpcdn.com/bphoto/FurcfTuqaYBv_q34bGTK5g/ms.jpg"
},
{
"name": "Bar Oldenhof",
"url": "https://www.yelp.com/biz/bar-oldenhof-amsterdam?adjust_creative=ycRBsh7KEkNFq3wJvKoL6Q&utm_campaign=yelp_api&utm_medium=api_v2_search&utm_source=ycRBsh7KEkNFq3wJvKoL6Q",
"snippet_text": "So I'm not much of a drinker. My taste is highly selective and I usually prefer not to drink alcohol altogether. But my husband is the opposite so on a...",
"image_url": "https://s3-media4.fl.yelpcdn.com/bphoto/1k57z7ziIW8MyAWHlXWGdg/ms.jpg"
},
{
"name": "Beer Temple",
"url": "https://www.yelp.com/biz/beer-temple-amsterdam?adjust_creative=ycRBsh7KEkNFq3wJvKoL6Q&utm_campaign=yelp_api&utm_medium=api_v2_search&utm_source=ycRBsh7KEkNFq3wJvKoL6Q",
"snippet_text": "This is a great place to stop in and have some American craft beer. With 30+ taps and a seemingly never ending list of bottle selections, you have many...",
"image_url": "https://s3-media1.fl.yelpcdn.com/bphoto/yxUiYre1Y6ULqMhQ30NPOA/ms.jpg"
},
{
"name": "Tales & Spirits",
"url": "https://www.yelp.com/biz/tales-en-spirits-amsterdam?adjust_creative=ycRBsh7KEkNFq3wJvKoL6Q&utm_campaign=yelp_api&utm_medium=api_v2_search&utm_source=ycRBsh7KEkNFq3wJvKoL6Q",
"snippet_text": "This is exactly what every high-end cocktail bar should strive to have and be.\n\nFriendly staff: From the bartenders to the manager to the waitress. Everyone...",
"image_url": "https://s3-media4.fl.yelpcdn.com/bphoto/IElXytpbY0bpp7ZdjFdGvA/ms.jpg"
}
]
This exists in the MongoDB database:
{
"_id": {
"$oid": "57da26d8dcba0f51172f47b1"
},
"name": "Arendsnest",
"url": "https://www.yelp.com/biz/arendsnest-amsterdam-2?adjust_creative=ycRBsh7KEkNFq3wJvKoL6Q&utm_campaign=yelp_api&utm_medium=api_v2_search&utm_source=ycRBsh7KEkNFq3wJvKoL6Q",
"snippet_text": "The reigning Lord of Amsterdam beer bars. Popular and seats go fast...come early. Ask for the massive all-Dutch beer list and prepare to have your...",
"image_url": "https://s3-media2.fl.yelpcdn.com/bphoto/FurcfTuqaYBv_q34bGTK5g/ms.jpg"
}
How can I write a query in Node to loop through my array using name property and do a check on every object if it exists in the database and return the data?
No need to iterate the array, use the $or operator with a mapped array that has the fields you want to query.
Take the following example where you want to search for a match of two properties:
var yelp = [
{
"name": "Arendsnest",
"url": "url1",
"snippet_text": "foo",
"image_url": "bar.jpg"
},
{
"name": "Bar Oldenhof",
"url": "abc",
"snippet_text": "efg",
"image_url": "ms.jpg"
},
{
"name": "Beer Temple",
"url": "https://www.yelp.com/",
"snippet_text": "test",
"image_url": "ms.jpg"
},
{
"name": "Tales & Spirits",
"url": "https://www.yelp.com/",
"snippet_text": "This is exactly...",
"image_url": "ms.jpg"
}
],
query = yelp.map(function(item){ return { name: item.name, url: item.url }; });
db.collection.find({ "$or": query });
This will create an array that you can use as the $or expression in your find() method, equivalent to :
db.collection.find({
"$or": [
{
"name": "Arendsnest",
"url": "url1"
},
{
"name": "Bar Oldenhof",
"url": "abc"
},
{
"name": "Beer Temple",
"url": "https://www.yelp.com/"
},
{
"name": "Tales & Spirits",
"url": "https://www.yelp.com/"
}
]
})
For querying on single properties, say for instance you want to query on just the name field, better use the $in operator which is better optimised for such:
query = yelp.map(function(item){ return item.name; });
db.collection.find({ "name": { "$in": query } });

limit records in mongodb query [duplicate]

This question already has answers here:
Retrieve only the queried element in an object array in MongoDB collection
(18 answers)
Closed 7 years ago.
This is my document in MongoDB and I need to limit the output:
{
"_id": ObjectId("55880fb8c3addd201ee2f70e"),
"title": "Sales",
"level1": [{
"name": "Master",
"link": "/sales/master"
}, {
"name": "eCommerce",
"link": "/sales/ecommerce"
}]
}
My search query is:
db.collection.find({
title: "Sales",
"level1.name": "Master"
}, {
"title": 1,
"level1.name": 1,
"level1.name": "Master"
})
This is the expected output:
{
"_id": ObjectId("55880fb8c3addd201ee2f70e"),
"title": "Sales",
"level1": [{
"name": "Master",
"link": "/sales/master"
}]
}
You can use aggregation by $unwind level1 array to get expected result like following:
db.collection.aggregate({$unwind:"$level1"},{$match:{"level1.name":"Master","title" :"Sales"}})
If you want all under one array you can group it like :
db.collection.aggregate({$unwind:"$level1"},{$match:{"title" :"Sales","level1.name":"Master"}},{$group:{_id:"_id","title":{$first:"$title"},"level1":{$push:"$level1"}}})
Please try the below query :
db.collection.find({title :"Sales",
level1: {$elematch: {name" : "Master"}}},
{title : 1, level1.$ : 1});

Link documents using Map-Reduce approch in CouchDB

department {
"_id": "1",
"department": "Computers",
"type": "Department",
"room_no": "102",
"HOD": "Mr. G Rahul",
"floor": "1st Floor"
}
student {
"_id": "fdf370e2f43d4af1b505b8913502a5e4",
"_rev": "1-16df9a4cd45ca69009ab6c9767425a8e",
"student Name": "H Ravi",
"date_of_birth": "March 1, 1993",
"roll_no": "55",
"inter_marks": "820",
"secondary_marks": "420"
"department_id": "1",
"type": "student"
}
Map Function
function(doc) {
var id,department,student,hod,dob;
if(doc.type == 'student') {
id = doc.department_id;
dob = new Date(doc.date_of_birth)
student = doc;
}
}
emit(dob, {'_id': id,"student_doc": student});
}
After writing map function we call view by using URL "//localhost:5984/db_name/_design/design_name/_view/view_name". In that URL we will append ?include_docs=true after "view_name"("//localhost:5984/db_name/_design/design_name/_view/view_name/?include_docs=true") to get the docs of by using _id in emit, example: emit(dob,{"_id": id}) it will return the docs of linked id...My question is how can we access that docs in reduce function.
You can’t, the docs are fetched on query time, not on indexing time, so the reduce function never gets to see that data. Sorry!

Categories