How to use Group by with find in mongoose? - javascript

I have collection named "listing" with fields such as metadata and status. metadata is a object containing user object inside and status is a string.
The structure looks like this,
{ "status": "Active", "metadata": {
"user": {
"urlProfile": "",
"averageRating": 5,
"reviewCount": 2,
"userId": "1244324"
} } }
Now the status field have values such as "Active" and "Inactive". I need to group by those status and filter by the userId. so i have a function inside the helper as follows,
query: function (model, conditon, options) {
console.log(conditon, options);
return new Promise(function (resolve, reject) {
options = options || {};
model.find(conditon, {}, options).exec(function (error, data) {
if (error) {
reject(error);
}
resolve(data);
})
})
}
Question is how can i pass the group by along with the user id and query the data needed. Right now my querying part looks like this,
return dbService.query(sellerModel, {
'metadata.user.userId': userIdRetrieved
}, {});
how can i pass the group by condition? i looked for sample, did not find any solution till now.
Sample Collection
Expected Output:
[{
"Status": "Active",
"Results": {
"user": {
"urlProfile": "",
"averageRating": 5,
"reviewCount": 2,
"userId": "1244324"
}
}
}
,
{
"Status": "InActive",
"Results": {
"user": {
"urlProfile": "",
"averageRating": 5,
"reviewCount": 2,
"userId": "1244324"
}
}
}]

To get the desired output, you would need to use the aggregate method since it offers the operators which allow you to aggregate the documents and return the said result.
Consider constructing a pipeline that consists of a $group stage, whereby you aggregate the average rating via the $avg accumulator, the reviewCount with $sum and the other fields in the group using $first or $last. Your group by key is a subdocument with two fields Status and userId.
A final $project step would allow you to reshape the output from the above group aggregates to the desired form and the aggregate() method returns a query which you can then call exec() to get a Promise.
To explain the above framework, follow this example:
query: function (model, conditon, options) {
console.log(conditon, options);
options = options || {};
return model.aggregate([
{ "$match": conditon },
{
"$group": {
"_id": {
"Status": "$status",
"userId": "$metadata.user.userId"
},
"urlProfile": { "$first": "$metadata.user.urlProfile" },
"averageRating": { "$avg": "$metadata.user.averageRating" },
"reviewCount": { "$sum": "$metadata.user.reviewCount" }
}
},
{
"$project": {
"_id": 0,
"Status": "$_id.Status",
"Results": {
"user": {
"averageRating": "$averageRating",
"reviewCount": "$reviewCount",
"userId": "$_id.userId"
}
}
}
}
]).exec();
}

Related

Mapping JSON response to using JS

I have a JSON response coming in and I need to map it into an Object and return only the specific fields using js.
Here I have created an example response:
{
"Header": {
"SenderId": "IDMAN",
},
"Shipments": {
"Shipment": [
{
"ShipmentNumber": "KIOKLIOS32",
"Product": {
"value": "1234",
"description": "example desc"
},
"Services": {
"Service": [
{
"value": "0234",
"amount": null,
"unit": null,
}
]
},
...
}
There will be multiple Service's and I need the fields shipments.shipment.product.value and shipments.shipment.services.service.value (all of them from the list).
One of my ideas was to first try create a const:
if (response.status === 200) {
let data = await response.text();
const shipmentData = JSON.parse(data);
const destination = {
"Header": {
"SenderId": _.get(shipmentData, 'Header.SenderId'),
}
};
res.status(200)
.send(destination);
}
This way I can get the senderId but I cannot access the array.
In which way do I have to create my object to map all of this?

How to delete a paticular Object in an array inRethinkDB

I am Just trying to learn RethinkDB.I am little Bit Confused That how to delete an single Object in an array,What is the Exact query I have to use if i have to delete this Object
{
"name": "Ram" ,
"username": "B97bf210-c4d2d-11e6-b783-07b5fev048705"
}
from whoLikedIt Array
My data
{
"comments": [ ],
"id": "c242c74d-03d9-4963-9a22-4779facb8192" ,
.....
"views": 0 ,
"whoLikedIt": [
{
"name": "Vignesh Warar" ,
"username": "d97bf210-c42d-11e6-b783-07b5fe048705"
},
{
"name": "Ram" ,
"username": "B97bf210-c4d2d-11e6-b783-07b5fev048705"
},
]
.....
}
My Try
r.db('image').table('posts').get('c242c74d-03d9-4963-9a22-4779facb8192').update(
{whoLikedIt:r.row('whoLikedIt').filter({username:"B97bf210-c4d2d-11e6-b783-07b5fev048705"}).delete()}
)
Throws Me a error
e: Cannot nest writes or meta ops in stream operations. Use FOR_EACH instead in:
You want:
r.db('image').table('posts').get('c242c74d-03d9-4963-9a22-4779facb8192').update(function(row) {
return {whoLikedIt: row('whoLikedIt').filter(function(obj) {
return obj('username').ne("B97bf210-c4d2d-11e6-b783-07b5fev048705");
})};
})

Replace array element from rethinkdb if it exists,or else insert

{
"LOGIN": "ABC",
"MESSAGE_UNPROCESSED": [
{
"DATE": "20160219",
"MESSAGE": [
{
"address": "XYZ",
"date": "1468385398746"
},
{
"address": "PQR",
"date": "1468385398746"
}
]
},
{
"DATE": "20160220",
"MESSAGE": [
{
"address": "LMN",
"date": "1468385398746"
},
{
"address": "JXT",
"date": "1468385398746"
}
]
}
],
"id": "e1705cae-2a57-42b3-af2e-8458ae9a43bb"
}
I want to add message into the field where Login is ABC if DATE doesn't exist or if it exist I want to replace the entire object from doc
I tried this :
r.db('usersData').table('smsRaw').filter(function (row) {
return row('MESSAGE_UNPROCESSED')('DATE').contains('20160222').replace({"DUMP":"DUMP"})
})
error: Cannot nest writes or meta ops in stream operations. Use FOR_EACH instead in:
r.db("usersData").table("smsRaw").filter(function(var_13) {
return var_13("MESSAGE_UNPROCESSED")("DATE").contains("20160222").replace({"DUMP": "DUMP"});
})
so if records {"DATE":"2016018","MESSAGE":[{"address":"abc","Date":"121212"}]}
if this record doesn't exist in MESSAGE_UNPROCESSED it should be added using set_insert or else if date is existing like 2016020 then entire element from array should be replaced
r.db('usersData').table('smsRaw').get("7cd66671-bb01-483d-a148-12ed1b7c2d31").update(function(row) {
return {
MESSAGE_UNPROCESSED: r.branch(
row("MESSAGE_UNPROCESSED")('DATE').eq('20160222'),
row("MESSAGE_UNPROCESSED")('MESSAGE').merge({"DUMP":"DUMP"}),
row("MESSAGE_UNPROCESSED")('MESSAGE').replace({"NEW":"NEW"})
)
}
})
Cannot nest writes
I want to do this manipulation using python

Nested Query/Select for MongoDB

I'm trying to query my MongoDB structure, specifically the users table to get a specific field, address, but am having difficulty because I'm not sure how to access something a couple levels in users > emails > address:
{
"_id": "BkWk7hq4MRyMAyK4mm",
"createdAt": ISODate("2015-11-15T19:46:41.633Z"),
"services": {
"password": {
"bcrypt": "$2a$10$voVzU3pIVZBd1bfJf1oX4.OMPnzi8zXawYY5REtovPayBJL7dZLWSC"
},
"resume": {
"loginTokens": []
}
},
"emails": [{
"address": "brutus#example.com",
"verified": false,
"provides": "default"
}],
"roles": {
"J8Bhq3uTtdgwZdx3rz": ["guest", "account/profile"]
}
} {
"_id": "3qfCgFz9r5wKjnmymQ",
"createdAt": ISODate("2015-12-15T19:49:05.236Z"),
"emails": [],
"roles": {
"J8aBhq3uTtdgwZx3rz": ["anonymous", "guest"]
},
"services": {
"resume": {
"loginTokens": [{
"when": ISODate("2015-12-15T19:49:05.280Z"),
"hashedToken": "c1ybS3U3+GeC8ZNzGQ3WOctWpudQvv4vND6EzlRygtCQ="
}]
}
}
}
I was trying to use the following:
db.users.find( { emails: { address : "brutus#example.com" } } )
You can query nested objects with dot notation.
db.users.find( { 'emails.address' : "brutus#example.com" } )
Your query is correct but it is querying documents for a complete match. So if your emails field had only address field it would work.
With dot notation you can check just one embedded field for matching.
Take a look at the documentation.

Deleting item mongodb and node async

I've having trouble removing a item from the upload [] object.
The below represents a User, keys[] represents a key for which file uploads get associated with, and uploads[] are files beneath that key. These are all documents embedded within the User model. I realize now I'd have been way better off using references but I am stuck with this for now. Here is the function I'm using right now to find the uploads item,
______________THIS IS MY CURRENT FUNCTION_____________________
I'll be honest I am using async and I don't exactly understand it well. Is there a different async function or way to lookup these items in mongo that would work better?
Current issues: 1) This will continue looping through until the end even after it finds the correct items. 2) How can I delete the upload item?
exports.getApiDelete = function (req, res, next) {
User.findById(req.user.id, function(err, user) {
if (err) return next(err);
console.log("User ID found: "+ user._id);
//loop though user keys
async.forEach(user.profile.keys, function(item, callback) {
//verify key exists
if(item.key==req.params.scriptkey){console.log("KEY FOUND")};
async.forEach(item.uploads, function(item, callback) {
//verify file exits
console.log(req.params.file_id);
if(item._id == req.params.file_id){
// DELETE FUNCTION HERE?
};
}, function(err){
console.log('Error during async lookup: '+err);
});
}, function(err){
console.log('Error during async lookup: '+err);
});
});
};
______________________________THIS MY USER MODEL_____________________
{
"__v": 19,
"_id": {
"$oid": "53c812c4e75ab0b013f3c6bc"
},
"email": "fake#mailinator.com",
"password": "fake",
"profile": {
"gender": "",
"keys": [
{
"_id": {
"$oid": "53c8130ae75ab0b013f3c6bd"
},
"status": false,
"iteration": 0,
"created": {
"$date": "2014-07-17T18:16:42.568Z"
},
"uploads": [],
"description": "This is being run from my Windows Desktop.",
"location": "Front Row",
"name": "fake_Desktop",
"key": "80f94c80-0dde-11e4-ae14-43922f7b8f23"
},
{
"_id": {
"$oid": "53c814ade75ab0b013f3c6be"
},
"created": {
"$date": "2014-07-17T18:23:41.777Z"
},
"description": "Windows VM test.",
"iteration": 12,
"key": "7ad78410-0ddf-11e4-ae14-43922f7b8f23",
"location": "Back Right",
"name": "fake2_Desktop",
"status": false,
"uploads": [
{
"_id": {
"$oid": "53c81517e75ab0b013f3c6bf"
},
"ip": "10.0.1.156",
"fname": "hklm_1.txt",
"iteration": 1,
"created": {
"$date": "2014-07-17T18:25:27.241Z"
},
"filepath": "script_uploads/7ad78410-0ddf-11e4-ae14-43922f7b8f23_1_hklm_1.txt"
},
{
"_id": {
"$oid": "53c8151ae75ab0b013f3c6c0"
},
"ip": "10.0.1.156",
"fname": "hklm_1.txt",
"iteration": 2,
"created": {
"$date": "2014-07-17T18:25:30.634Z"
},
"filepath": "script_uploads/7ad78410-0ddf-11e4-ae14-43922f7b8f23_2_hklm_1.txt"
}
]
}
}
You want to remove only from array? If yes, use
for(var i =0, j = item.uploads.length; i < j; i++) {
//verify file exits
console.log(req.params.file_id);
if(item.uploads[i]._id == req.params.file_id){
item.uploads.slice(i, 1);
};
And at the end use: user.save(function(err){});
If there is anything you want to delete from file system, use:
fs = require('fs');
fs.unlink( FILE PATH , function(err) {
console.log(err);
});
Also you don't really need async version of forEach, cause User.findById is asynchronous itself and whole process goes on background.
This will continue looping through until the end even after it finds
the correct items.
There is no "break" for async.forEach. So if you don't want to do unwanted process, use for as I did and append a break point.
There is no async call inside your loops, so you don't need async.forEach(). Using javascript native loops would be just fine:
exports.getApiDelete = function (req, res, next) {
User.findById(req.user.id, function(err, user) {
if (err) return next(err);
console.log("User ID found: "+ user._id);
user.profile.keys.forEach(function(el) {
if(el.key==req.params.scriptkey){console.log("KEY FOUND");}
el.uplaods.forEach(function(item) {
console.log(req.params.file_id);
if(item._id == req.params.file_id){
// DELETE FUNCTION HERE?
}
});
});
});
};

Categories