I meet some trouble need your help ~~ thx
I am use mongoose + superAgent + feedparser + eventProxy to get Rss and save these datas
now I can get and finish parse these dataes however I can't save them with moogose
I have 3 module are dao.js , app.js and service.js
I configure dao as this codes
var mongoose = require("mongoose"),
db,
modelName = "news"; // 设定操作的collections
mongoose.connect("mongodb://localhost:27017/test");
db = mongoose.connection;
db
.on("error", function (err) {
console.log("Connection Error!!! this's some prompts: ");
console.log(err);
})
.once("open", function () {
console.log("Open DataBase Successfully!!!");
});
// 设置
var newsSchema = mongoose.Schema({
"category": String,
"data": [{
"title": String,
"link": String,
"pubDate": String,
"source": String,
"author": String
}]
});
console.log(newsSchema.ObjectId);
newsSchema.pre("save", function (next) {
if( !this.title ) {
this.title = "未知标题";
}
next();
})
var newsModel = mongoose.model(modelName, newsSchema);
module.exports = {
model: newsModel,
schema: newsSchema,
mongoose,
db
}
and save data as these codes:
saveData(callback) {
var $self = this;
for(var i = 0; i<$self.result.length; i++) {
new model($self.result[i]).save(function (err) {
if(err) {
console.log(err)
} else {
console.log("数据存储成功!")
}
});
}
callback && callback();
db.close();
}
Now the data can't save successfully meanwhile the save callback func don't run
Could you give me some advise?
Related
I use update Query for push some data in array in Mongodb and I use mongoose in nodeJs.Pplease anyone can help out from this.
Model Schema :
var mongoose = require('mongoose')
var Schema = mongoose.Schema;
var bcrypt = require('bcrypt')
var schema = new Schema({
email: { type: String, require: true },
username: { type: String, require: true },
password: { type: String, require: true },
creation_dt: { type: String, require: true },
tasks : []
});
module.exports = mongoose.model('User',schema)
So I use this schema and I want to push data in tasks array and here is my route code for pushing data.
Route For Update Data in Tasks:
router.post("/newTask", isValidUser, (req, res) => {
addToDataBase(req, res);
});
async function addToDataBase(req, res) {
var dataa = {
pName: req.body.pName,
pTitle: req.body.pTitle,
pStartTime: req.body.pStartTime,
pEndTime: req.body.pEndTime,
pSessionTime: req.body.pSessionTime,
};
var usr = new User(req.user);
usr.update({ email: req.user.email }, { $push: { tasks: dataa } });
console.log(req.user.email);
try {
doc = await usr.save();
return res.status(201).json(doc);
} catch (err) {
return res.status(501).json(err);
}
}
Here I create a async function and call that function in route but when I post data using postman it response with status code 200(success) but it updates nothing in my database.
Output screenshot:
as you can see in this image task : [].. it updates nothing in that array but status is success
I don't know why is this happening.
You can achieve this task easier using findOneAndUpdate method.
router.put("/users", isValidUser, async (req, res) => {
var data = {
pName: req.body.pName,
pTitle: req.body.pTitle,
pStartTime: req.body.pStartTime,
pEndTime: req.body.pEndTime,
pSessionTime: req.body.pSessionTime,
};
try {
const user = await User.findOneAndUpdate(
{ email: req.user.email },
{
$push: {
tasks: data,
},
},
{ new: true }
);
if (!user) {
return res.status(404).send("User with email not found");
}
res.send(user);
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong");
}
});
Also I strongly suggest using raw / JSON data for request body, that's how most ui libraries (reactjs, angular) send data.
To be able to parse json data, you need to add the following line to your main file before using routes.
app.use(express.json());
TEST
Existing user:
{
"tasks": [],
"_id": "5e8b349dc285884b64b6b167",
"email": "test#gmail.com",
"username": "Kirtan",
"password": "123213",
"creation_dt": "2020-04-06T14:21:40",
"__v": 0
}
Request body:
{
"pName": "pName 1",
"pTitle": "pTitle 1",
"pStartTime": "pStartTime 1",
"pEndTime": "pEndTime 1",
"pSessionTime": "pSessionTime 1"
}
Response:
{
"tasks": [
{
"pName": "pName 1",
"pTitle": "pTitle 1",
"pStartTime": "pStartTime 1",
"pEndTime": "pEndTime 1",
"pSessionTime": "pSessionTime 1"
}
],
"_id": "5e8b349dc285884b64b6b167",
"email": "test#gmail.com",
"username": "Kirtan",
"password": "123213",
"creation_dt": "2020-04-06T14:21:40",
"__v": 0
}
Also as a side note, you had better to create unique indexes on username and email fields. This can be done applying unique: true option in the schema, but better to create these unique indexes at mongodb shell like this:
db.users.createIndex( { "email": 1 }, { unique: true } );
db.users.createIndex( { "username": 1 }, { unique: true } );
It's been awhile since I've done mongoose, but I'm pretty sure <model>.update() also actively updates the record in Mongo.
You use .update() when you want to update an existing record in Mongo, but you are instantiating a new User model (i.e. creating a new user)
try the following code instead for a NEW USER:
router.post('/newTask', isValidUser, (req, res) => {
addToDataBase(req,res)
})
async function addToDataBase(req, res) {
var dataa = {
pName: req.body.pName,
pTitle: req.body.pTitle,
pStartTime: req.body.pStartTime,
pEndTime: req.body.pEndTime,
pSessionTime: req.body.pSessionTime
}
// email field is already in `req.user`
var usr = new User({ ...req.user, tasks: [dataa] });
console.log(req.user.email);
try {
await usr.save();
return res.status(201).json(doc);
}
catch (err) {
return res.status(501).json(err);
}
}
Now, if you wanted to update an existing record :
router.post('/newTask', isValidUser, (req, res) => {
addToDataBase(req,res)
})
async function addToDataBase(req, res) {
var dataa = {
pName: req.body.pName,
pTitle: req.body.pTitle,
pStartTime: req.body.pStartTime,
pEndTime: req.body.pEndTime,
pSessionTime: req.body.pSessionTime
}
try {
await usr. updateOne({ email : req.user.email}, { $push: { tasks: dataa } });
return res.status(201).json(doc);
}
catch (err) {
return res.status(501).json(err);
}
}
For more info read: https://mongoosejs.com/docs/documents.html
I am trying to populate my array of an object id's how can i do ??
Function
$scope.assignEmployees = function () {
var chkArray = [];
var companyName = $scope.selectedComapny.companyName;
var Indata = {chkvalue:chkArray,company_name:companyName};
$("#employee_name:checked").each(function() {
chkArray.push($(this).val());
});
$http({
method : 'PUT',
url : '/api/projects',
data : Indata
})
.success(function (data){
console.log(data);
});}
Mongoose api
Population code:-
Project.findOne({client : company_name})
.populate('assignedTo')
.exec(function(err, project) {
if (err) return;
while(i<employee_id.length){
project.assignedTo.push(employee_id[i]);
project.save(function(err) {
if (err) return;
})
i++;
}
});
This code is work but it insert value 4 times any idea guys.
You can use this code to push all elements of Array to an Array in mongoose.
Project.update(
{ client: company_name },
{ "$pushAll": { "assignedTo": employee_id } },
function (err, raw) {
if (err) return handleError(err);
console.log('The raw response from Mongo was ', raw);
}
);
i am trying to make a game. I need tu create a Match. I think the problem on this Way. The User create a Match. In a third table I save playerId and gameId. When another user join the match, I save again, playerId and gameId. Then, I make a query with player with gameId in common, and start the game.
first, One User may have many Games. second, One Match may have many Games. this is the Match model:
module.exports = {
attributes: {
name: {
type: 'string'
},
description: {
type: 'string'
},
game: {
collection: 'game',
via: 'gameId',
}
}
};
This is the User model:
var bcrypt = require('bcrypt');
module.exports = {
attributes: {
name: {
type:'string'
},
email: {
type: 'email',
required: true,
unique: true
},
password: {
type: 'string',
},
passwordConfirmation: {
type: 'string'
},
passwordEncrypted: {
type: 'string'
},
creator: {
collection: 'game',
via: 'playerId'
},
toJSON: function(){
var obj = this.toObject();
delete obj.password;
delete obj.passwordConfirmation;
delete obj._csrf;
return obj;
}
}, beforeCreate: function(values, next){
console.log("Acabo de entrar a eforeCreate");
var password = values.password;
var passwordConfirmation = values.passwordConfirmation;
if(!password || !passwordConfirmation || password != values.passwordConfirmation) {
var passwordDoesNotMatchError = [{
name: 'passwordDoesNotMatchError',
message: 'Las contraseñas deben coincidir'
}]
return next({
err: passwordDoesNotMatchError
});
}
require('bcrypt').hash(values.password, 10, function passwordEncrypted(err, EncryptedPassword){
values.EncryptedPassword = EncryptedPassword;
next();
});
}
};
This is the Game model:
module.exports = {
attributes: {
gameId: {
model: 'match'
},
playerId: {
model: 'user'
}
}
};
finally, this is my controller:
module.exports = {
createMatch: function(req,res){
var matchObj = {
name: req.param('name'),
description: req.param('description'),
}
Match.create(matchObj, function(err, match){
if(err){
console.log("el error fue: " + err);
return res.send(err);
} console.log("Entro en create");
return res.json(match);
})
var gameObj = {
gameId: 'aclaration: I dont know how do I get the match.id',
playerId: req.session.me
}
Game.create(gameObj,function(err,game){
console.log("entro a GameCreate");
if(err){
return res.send(err);
} return res.json(game);
})
}
};
I can create the Match, but Game.create send this error:
_http_outgoing.js:344 throw new Error('Can\'t set headers after they are sent.'); ^
Error: Can't set headers after they are sent.
Somebody can help me? probably, I have many errors. Thanks.
Couple of things here:
Having an explicit Game model is not required in Sails. It can manage it implicitly, unless you want to store more information than just gameId and userId. So, you can just do away with Game model.
Please refer for async programming: How do I return the response from an asynchronous call?
Below code should work for you. Hope it helps.
module.exports = {
createMatch: function(req, res) {
var matchObj = {
name: req.param('name'),
description: req.param('description'),
};
Match.create(matchObj, function(err, match) {
if (err) {
console.log("el error fue: " + err);
return res.send(err);
}
console.log("Entro en create");
var gameObj = {
gameId: match.id,
playerId: req.session.me
};
Game.create(gameObj, function(err, game) {
console.log("entro a GameCreate");
if (err) {
return res.send(err);
}
return res.json(game);
// return res.json(match);
});
});
}
};
I'm new to server-side programming, and I'm trying to understand how to send data server-side, find a document in a collection and compare it against that data, and then send a status back to the client depending on whether or not it exists.
Here's what's being sent server-side via the /login post request:
{"email":"johndoe#gmail.com","password":"pass"}
Here's the document I'm wanting to compare against in the users collection in my DB:
{
"_id" : ObjectId("580bcf9874ae28934705c0fc"),
"email" : "johndoe#gmail.com",
"password" : "pass"
}
And here's my server-side script (areas I'm guessing are problematic have comments above them):
var express = require("express");
var app = express();
var bodyParser = require("body-parser");
var fs = require("fs");
var mongoose = require("mongoose");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(express.static("./public"));
mongoose.connect('mongodb://localhost:27017', function (err, db) {
app.post("/login", function(req, res) {
var emailRegex = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
var userInDb;
// ***** HERE 1 ******
db.collection("users").findOne( {"email": req.body["email"], "password": req.body["password"]} ).toArray(function(err, results) {
userInDb = results;
db.close();
});
// ***** HERE 2 ******
var emailInDb = userInDb["email"];
var passwordInDb = userInDb["password"];
if (!req.body["email"] || !req.body["password"]) {
res.sendStatus(403);
} else if ( !emailRegex.test(req.body["email"])) {
res.sendStatus(403);
} else if ( (req.body["email"] != emailInDb) && (req.body["password"] != passwordInDb) ) {
res.sendStatus(403);
} else {
res.sendStatus(200);
}
});
});
I've also experimented with the following in place of the "HERE 1" section:
var findUser = function (db, callback) {
var users = db.collection("users");
users.findOne({"email": req.body["email"], "password": req.body["password"]}).toArray(function(err, results) {
userInDb = results;
callback(results);
});
=================== EDIT ========================
Here's what it looks like after implementing the below:
mongoose.connect('mongodb://localhost:27017', function (err, db) {
app.post("/login", function(req, res) {
var emailRegex = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
var userInDb;
if (!req.body["email"] || !req.body["password"]) {
return res.sendStatus(403);
} else if ( !emailRegex.test(req.body["email"])) {
return res.sendStatus(403);
} else {
db.collection("users").findOne( {"email": req.body["email"], "password": req.body["password"]}, function(err, results) {
if(err || !result) {
return res.sendStatus(403);
} else {
userInDb = results;
db.close();
return res.sendStatus(200);
}
});
}
});
});
But I'm getting this error in the terminal:
POST request for '/login' - {"email":"johndoe#gmail.com","password":"pass"}
TypeError: Cannot read property 'collection' of undefined at app.js:30:6
Here's what's at line 30:
db.collection("users").findOne( {"email": req.body["email"], "password": req.body["password"]}, function(err, results) {
Does the collection need to be stored somewhere other than the /db/data/ folder you set up when installing MongoDB, do I need to mongoose.connect directly to the users collection, or something else?
findOne is an async function, you have to put the code above here 2 on the callback like this :
db.collection("users").findOne( {"email": req.body["email"], "password": req.body["password"]} ).toArray(function(err, results) {
// ***** HERE 2 ******
var emailInDb = userInDb["email"];
var passwordInDb = userInDb["password"];
.....
});
Then, you forget to check error and result,
db.collection("users").findOne( {"email": req.body["email"], "password": req.body["password"]} ).toArray(function(err, results) {
if(err || !result)
res.sendStatus(403);
// ***** HERE 2 ******
var emailInDb = userInDb["email"];
var passwordInDb = userInDb["password"];
.....
});
Then, you call findOne with the toArray function, why ? You only want 1 result, you don't need to transformed it. In addition you don't use the result as an array, so replace it with
db.collection("users").findOne( {"email": req.body["email"], "password": req.body["password"]}, function(err, results) {
if(err || !result)
return res.sendStatus(403);
// ***** HERE 2 ******
var emailInDb = userInDb["email"];
var passwordInDb = userInDb["password"];
.....
});
Finally, do control before mongo call to prevent useless db call and no need to check (req.body["email"] != emailInDb) && (req.body["password"] != passwordInDb) as it has been already done in mongo query.
Final code :
var emailInDb = userInDb["email"];
var passwordInDb = userInDb["password"];
if (!req.body["email"] || !req.body["password"]) {
return res.sendStatus(403);
} else if ( !emailRegex.test(req.body["email"])) {
return res.sendStatus(403);
} else {
db.collection("users").findOne( {"email": req.body["email"], "password": req.body["password"], function(err, results) {
if(err || !result)
return res.sendStatus(403);
else
{
userInDb = results;
db.close();
return res.sendStatus(200);
}
});
});
}
Other optimisations :
you don't need to put your call in the mongo db connect callback.
hash your password in db
================ EDIT =============
Don't use db.collection
File app.js
var mongoose = require("mongoose");
var User = require("./models/User");
mongoose.connect('mongodb://localhost:27017');
app.post("/login", function(req, res) {
var emailRegex = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
var userInDb;
if (!req.body["email"] || !req.body["password"]) {
return res.sendStatus(403);
} else if ( !emailRegex.test(req.body["email"])) {
return res.sendStatus(403);
} else {
Users.findOne( {"email": req.body["email"], "password": req.body["password"]}, function(err, results) {
if(err || !results) {
return res.sendStatus(403);
} else {
return res.sendStatus(200);
}
});
}
});
app.listen(....
File models/User.js
var mongoose = require('mongoose');
var userSchema = new mongoose.Schema({
// auth fields
email: {type: String, unique: true, lowercase: true },
password: {type: String, default: ""}
... other fields
});
module.exports = mongoose.model('User', userSchema);
I've looked through the mongoose API, and many questions on SO and on the google group, and still can't figure out updating embedded documents.
I'm trying to update this particular userListings object with the contents of args.
for (var i = 0; i < req.user.userListings.length; i++) {
if (req.user.userListings[i].listingId == req.params.listingId) {
User.update({
_id: req.user._id,
'userListings._id': req.user.userListings[i]._id
}, {
'userListings.isRead': args.isRead,
'userListings.isFavorite': args.isFavorite,
'userListings.isArchived': args.isArchived
}, function(err, user) {
res.send(user);
});
}
}
Here are the schemas:
var userListingSchema = new mongoose.Schema({
listingId: ObjectId,
isRead: {
type: Boolean,
default: true
},
isFavorite: {
type: Boolean,
default: false
},
isArchived: {
type: Boolean,
default: false
}
});
var userSchema = new mongoose.Schema({
userListings: [userListingSchema]
});
This find also doesn't work, which is probably the first issue:
User.find({
'_id': req.user._id,
'userListings._id': req.user.userListings[i]._id
}, function(err, user) {
console.log(err ? err : user);
});
which returns:
{ stack: [Getter/Setter],
arguments: [ 'path', undefined ],
type: 'non_object_property_call',
message: [Getter/Setter] }
That should be the equivalent of this mongo client call:
db.users.find({'userListings._id': ObjectId("4e44850101fde3a3f3000002"), _id: ObjectId("4e4483912bb87f8ef2000212")})
Running:
mongoose v1.8.1
mongoose-auth v0.0.11
node v0.4.10
when you already have the user, you can just do something like this:
var listing = req.user.userListings.id(req.params.listingId);
listing.isRead = args.isRead;
listing.isFavorite = args.isFavorite;
listing.isArchived = args.isArchived;
req.user.save(function (err) {
// ...
});
as found here: http://mongoosejs.com/docs/subdocs.html
Finding a sub-document
Each document has an _id. DocumentArrays have a special id method for looking up a document by its _id.
var doc = parent.children.id(id);
* * warning * *
as #zach pointed out, you have to declare the sub-document's schema before the actual document 's schema to be able to use the id() method.
Is this just a mismatch on variables names?
You have user.userListings[i].listingId in the for loop but user.userListings[i]._id in the find.
Are you looking for listingId or _id?
You have to save the parent object, and markModified the nested document.
That´s the way we do it
exports.update = function(req, res) {
if(req.body._id) { delete req.body._id; }
Profile.findById(req.params.id, function (err, profile) {
if (err) { return handleError(res, err); }
if(!profile) { return res.send(404); }
var updated = _.merge(profile, req.body);
updated.markModified('NestedObj');
updated.save(function (err) {
if (err) { return handleError(res, err); }
return res.json(200, profile);
});
});
};