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?
}
});
});
});
};
Related
how come wouldn't Mongoose and Mongosh return the same answer?
In the Schema, I have user ID and IoT device (smart light). Goal that I am trying to achieve is to remove completely first item in "smart_light" section.
Using Mongosh code works fine, but Mongoose is not removing the item. No errors are thrown, just "{acknowledged: false}". Mongoose is used with Node.
Schema (I am using replica set):
{
"UserID": "6276a2a6e59469e642801f4f",
"smart_light": {
"1": {
"Device_ID": "1",
"Device_Details": {
"Online_Status": true,
"DeviceManufacturer": "Philips",
"Model": "S-Li-7",
"Serial_Number": "302504-519574",
"Last_Update": {
"Date": "2014-05-11 19:59:37",
"Version": "V4",
"Update_Pending": false
},
"Communication_Protocol_Set": [
"Zigbee",
"Zwave"
],
"Spare_Parts": [
"Bridge"
]
},
"Device_Status": {
"Colour": "#08b8cd"
}
},
"2": {
"Device_ID": "2",
"Device_Details": {
"Online_Status": true,
"DeviceManufacturer": "Philips",
"Model": "S-Li-5",
"Serial_Number": "136985-212439",
"Last_Update": {
"Date": "2011-08-16 03:45:29",
"Version": "V2",
"Update_Pending": true
},
"Communication_Protocol_Set": [
"Zwave"
],
"Spare_Parts": [
"Bridge"
]
},
"Device_Status": {
"Colour": "#4bf14b"
}
}
}
}
Mongosh:
db.iot_customer_devices.updateOne(
{UserID: "6276a2a6e59469e642801f4f"},
{"$unset":{"smart_light.1":""}});
Mongoose:
IoT_Customer_Device.updateOne(
{UserID: "6276a2a6e59469e642801f4f"},
{$unset: {"smart_light.1":""}},
{ safe: true, multi:true },
function(err, result) {
if (err) {
console.log(err);
} else {
console.log(result);
}}
);
===================================================================
Update1:
It seems that if I try to remove (with mongoose) "UserID", this works... But objects cannot be removed so far?
IoT_Customer_Device.findOneAndUpdate(
{ UserID: "6276a2a6e59469e642801f18" },
{$unset: {"UserID":1}}, (err, res) => {
console.log(res);
});
This is now closed, answer has been found:
IoT_Customer_Device.updateOne(
{ UserID: "6276a2a7e59469e642801f86" },
[
{ $unset: "smart_light.1" }
],
(err, data) => {
if (!err) {
res.redirect('/devices/smart_light');
}
else { console.log('Error in device delete :' + err); }
}
);
This is working as intended, found my inspiration here
I saw a few questions like mine but couldn't find any solutions that worked so I thought I'd ask.
I'm trying to pull all my data from my database so I can select parts of it in my app. I had my database working fine but when I tried to pull the pictures it failed and keeps giving me this error and also does not seem to receive the data from the database:
app.model.users.find((err,result)=>{
^
TypeError: Cannot read property 'find' of undefined
Here is my code:-
server.js:-
'use strict';
const loopback = require('loopback');
const boot = require('loopback-boot');
const app = module.exports = loopback();
app.start = function() {
// start the web server
return app.listen(function() {
app.emit('started');
const baseUrl = app.get('url').replace(/\/$/, '');
console.log('Web server listening at: %s', baseUrl);
if (app.get('loopback-component-explorer')) {
const explorerPath = app.get('loopback-component-explorer').mountPath;
console.log('Browse your REST API at %s%s', baseUrl, explorerPath);
}
});
};
// Bootstrap the application, configure models, datasources and middleware.
// Sub-apps like REST API are mounted via boot scripts.
boot(app, __dirname, function(err) {
if (err) throw err;
// start the server if `$ node server.js`
if (require.main === module)
app.start();
});
console.log(Object.keys(app.models));
app.model.users.find((err,result)=>{
if(result.length ===0){
const user={
email:'jhanvi#gmail.com',
password:'jhanvi',
username: 'jhanvi',
};
app.models.user.create(user,(err,result)=>{
console.log("tried to create user ",err,result);
});
}
});
app.models.user.afterRemote('create', (ctx,user,next) =>{
console.log("new user is",user);
app.models.Profile.create({
first_name: user.username,
created_at: new Date(),
userId: user.id
},(err,result)=>{
if(!err && result){
console.log("created new profile",result);
}
else{
console.log("there is an error ",err);
}
});
next();
});
user.json:-
{
"name": "user",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"email": {
"type": "string"
},
"password": {
"type": "string"
}
},
"validations": [],
"relations": {
"Profile": {
"type": "hasMany",
"model": "Profile",
"foreignKey": ""
},
"accessTokens":{
"type":"hasMany",
"model":"CustomAccessToken",
"foreignKey":"userId"
}
},
"acls": [],
"methods": {}
}
Profile.json :-
{
"name": "Profile",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"first_name": {
"type": "string"
},
"last_name": {
"type": "string"
},
"created_at": {
"type": "date"
},
"age": {
"type": "number"
},
"history": {
"type": [
"object"
]
}
},
"validations": [],
"relations": {
"user": {
"type": "belongsTo",
"model": "user",
"foreignKey": "userId"
}
},
"acls": [],
"methods": {}
}
In your model you refer to user.
app.model.users.find((err,result)
should then surely be
app.model.user.find((err,result)
(i see you seem to be using both versions...)
I am doing a Node.js REST API tutorial. I use Express, Knex.js (0.19.0) and PostgreSQL.
I have two database tables, users:
// user_migration.js
exports.up = function(knex) {
return knex.schema.createTable('users', function(table) {
table
.increments('id')
.primary()
.unsigned();
table.string('firstName');
table
.string('lastName')
.index()
.notNullable();
table
.string('email')
.unique()
.index()
.notNullable();
table.string('password').notNullable();
table.string('role').defaultTo('STAFF');
table.boolean('isActive').defaultTo(false);
table.timestamp('createdAt').defaultTo(knex.fn.now());
table.timestamp('updatedAt').defaultTo(knex.fn.now());
});
};
and posts:
// post_migration.js
exports.up = function(knex) {
return knex.schema.createTable('posts', function(table) {
table
.increments('id')
.primary()
.unsigned();
table.string('title').notNullable();
table.text('body');
table.boolean('published').defaultTo(false);
table
.integer('author')
.unsigned()
.index()
.references('id')
.inTable('users')
.onDelete('SET NULL');
table.timestamp('createdAt').defaultTo(knex.fn.now());
table.timestamp('updatedAt').defaultTo(knex.fn.now());
});
};
I want to make a GET request at http://localhost:8081/users/1/posts to show user.id 1's posts.
// user_get.js
async getPosts(req, res, next) {
try {
// Check if user exists
const user = await this.knex('users')
.where('id', req.params.id)
.first();
// If not, return NOT FOUND status code
if (!user) return next(createError(404, 'User not found'));
/**
* Right here, I am not sure if I am doing it right.
*/
// Get from database and filter
const result = await this.knex('users')
.join('posts', 'posts.author', '=', 'users.id')
.select()
.then(posts => posts.filter(post => post.author === user.id));
// Return OK status code and related posts
res.status(200).send(result);
} catch (error) {
// Return BAD REQUEST status code
return next(createError(400, error);
}
}
What I expected is an array of posts belong to user 1:
[
{
"id": 1,
"title": "Number One Post",
"body": "This is the one body",
"published": true,
"author": 1,
"createdAt": "2019-07-23T06:14:04.281Z",
"updatedAt": "2019-07-23T06:14:04.281Z"
},
{
"id": 2,
"title": "Number Two Post",
"body": "This is two body",
"published": false,
"author": 1,
"createdAt": "2019-07-23T06:14:04.281Z",
"updatedAt": "2019-07-23T06:14:04.281Z"
}
]
But I got like this:
[
{
"id": 1,
"firstName": "Some",
"lastName": "One",
"email": "some#one.com",
"password": "password789",
"role": "STAFF",
"isActive": false,
"createdAt": "2019-07-23T06:14:04.281Z",
"updatedAt": "2019-07-23T06:14:04.281Z",
"title": "Number One Post",
"body": "This is the one body",
"published": true,
"author": 1
},
{
"id": 2,
"firstName": "Some",
"lastName": "One",
"email": "some#one.com",
"password": "password789",
"role": "STAFF",
"isActive": false,
"createdAt": "2019-07-23T09:21:34.285Z",
"updatedAt": "2019-07-23T09:21:34.285Z",
"title": "Number Two Post",
"body": "This is two body",
"published": false,
"author": 1
}
]
How should I query user 1's posts without mashing up with user info?
Please help.
P.S. Also updatedAt in Knex.js does not work correctly. It does not update the timestamp when I update. How do I fix this?
Just drop your join on users in the second query
const result = await this.knex('posts')
.where('posts.author', user.id)
.select()
// Return OK status code and related posts
res.status(200).send(result);
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();
}
I am having problem when I pass the node .get to show the result the array wraps the data result.
[
{
"book_id": 1,
"title": "HARRY",
"pages": "123",
"image": ""
}
]
Is there way to make the result show like this without array?
{
"book_id": 1,
"title": "HARRY",
"pages": "123",
"image": ""
}
This is code for node to fetch data from sql.
app.get('/books/:id', function(req, res, next) {
db.get_individual([req.params.id], function(err, individual) {
if(err) res.status(500).send(err);
else res.send(individual);
});
});
This is the Sql query
SELECT * FROM book;
You can send the object at [0]:
res.send(individual[0]);