mongodb array data store using node js - javascript

I have to try to store my child info into MongoDB via using postman tool. But it shows me this message "message": "child info validation failed"
in postman console. child info is my collection name where I store my child info.
my requirement is to store the result in array form as below schema mentioned inside MongoDB
1). This is js child schema
userId:{
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
quiz:[
{
questionId:{
type: mongoose.Schema.Types.ObjectId,
ref: 'questions'
},
score:{type:String},
time:{type:String}
}
]
2). This is node js
try {
var quizArr = [];
var quizObj = {
'questionId': req.params.questionId,
'score': req.params.score,
'time': new Date().toISOString()
};
quizArr.push(quizObj);
var userObj = {
'userid': req.params.userId,
'quiz': quizArr
};
//var parseObj = Json.stringify(userObj); This line is comment
var childinfoSave = new QuizChildInfo(userObj);
childinfoSave.save(function (err) {
if (err) return next(err);
res.send("Child questionId score and date saved successfully")
console.log("Child questionId score and date saved successfully");
});
}catch(err){console.log(err);}
3). Output of postman screen
{
"message": "childinfos validation failed"
}
4). Output of console
Mongoose: mpromise (mongoose's default promise library) is deprecated, plug in your own promise library instead: http://mongoosejs.com/docs/promises.html
5). Mongo console
{
"_id" : ObjectId("57bc483169e718642ac0ac44"),
"levelsAttempted" : [ ],
"quiz" : [ ],
"__v" : 0
}

For the problem of your console,
put mongoose.Promise = global.Promise; in the file where you have established your server connection( like in my case its index.js).
And i think you may have not posted the whole code as i couldnt find childinfos in your code.

Related

Mongoose : Cast to ObjectId failed for value "Some String" at path "_id"

New to MongoDB, Javascript stack and need help understanding cause of this error.
I have my model created :
const
Mongoose = require('mongoose');
Schema = Mongoose.Schema,
Model = Mongoose.model;
module.exports = Model('Project',
new Schema({
icon : String,
name : String,
state : String,
number : String
})
);
This is my MongoDB document :
[![MongoDB Document][1]][1]
I am attempting to receive all the documents in the collection when I call the API so therefore as per the Mongoose document I am using the find() method.
Here is my API Implementation:
const Project = require('../../models/project');
router.get('/projects/:page?/:limit?',
function(req, res, next){
const page = Math.max(req.params.page || 1, 1) - 1;
const limit = Math.max(req.params.limit || 20, 20);
//Verified : I am hitting the API
console.log("Reached API /projects");
Project.find()
.populate('icon')
.populate('name')
.populate('state')
.populate('number')
.limit(limit).skip(page * limit).exec(
function(err, project)
{
if (err) { return next(err); }
res.send(project);
}
); //End of exec()
}//End of unction
);
I am successful in making the API call using fetch() but I am receiving "Cast to ObjectId failed error" for all the String values.
I believe there is something really simple within my Mongo DB document that I might be missing. Please help me understand and solve this issue.
**EDIT ---
The error seems to point at the string values of the keys:
**
Thank you
Population is the process of automatically replacing the specified paths in the document with document(s) from other collection(s). So you're Id cast is not valid, because of string, you need to have ObjectId, some changes need to be made before it, Let's debug:
const alldata = await Project.find()
console.log(alldata) // ?
does this return something, I'm using async await here if it return data then the problem is with your populate because your Id case isn't valid as you save in schema string and you're referring here populate, example of using populate:
module.exports = Model('Project',
new Schema({
icon : [{ type: Schema.ObjectId, ref: 'your icon document' }],
name : [{ type: Schema.ObjectId, ref: 'you name document' }],
state : [{ type: Schema.ObjectId, ref: 'state document' }],
number : [{ type: Schema.ObjectId, ref: 'number document' }]
})
);
but it seems to me that you don't need to use the populate because you have simple data, name, number... so you should be good to go with the above example
Resources: mongoose fetching data, using populate, relation

How to update user.services for Jasmine testing in Meteor

I am trying to mock out a user for testing out my application, and I have gotten to the point where I can create a test user and log them into the mirror instance of my app.
I need to compare the gmail addresses for peoples accounts, and to test this functionality, I want to add a test email address under user.services.google.email within the Meteor users account database (which is where the accounts-google package stores it, I don't need to mock out an entire user account yet).
What I can't figure out is how to append this information, instead of just overwriting what is already there, this is what my code looks like:
if (Meteor.users.find().count() === 0) {
var testUserDetails = {
email: 'testEmail#gmail.com',
password: 'testPassword'
};
console.log("Creating the Test User");
var newUserId = Accounts.createUser(testUserDetails);
Meteor.users.update({
_id: newUserId
}, {
$set: {
services: {
google: {
email: "testEmail#gmail.com"
}
}
}
});
} else {
console.log("There are already users in the Test database");
}
console.log('***** Finished loading default fixtures *****');
},
And this is what a user looks like:
{
"_id" : "Dw2xQPDwKp58RozC4",
"createdAt" : ISODate("2015-07-30T04:02:03.261Z"),
"services" : {
"password" : {
"bcrypt" : "asdfasdfasdfdsafsadfasdsdsawf"
},
"resume" : {
"loginTokens" : [ ]
}
},
"emails" : [
{
"address" : "testEmail#gmail.com",
"verified" : false
}
]
}
Now $set just rewrites everything within services, and there is no $push operation for mongo or for js, so how should I go about doing this? Should I consume the object and parse it manually?
*Note I have also tried using Meteor's Accounts.onCreateUser(function(options, user) but facing the same issue.
[...] there is no $push operation for mongo [...]
Sure, there is a $push operator, which appends a specified value to an array.
However, I think what you are trying to do is to update a document and keep all values which are already set.
Here is how you can do that:
Query the document first to get the object you want to set.
Update the respective object.
Run the MongoDB update operation to set the new object.
For instance:
var user = Meteor.users.findOne({
_id: newUserId
});
var servicesUserData = user.services;
servicesUserData.google.email = "your_new_email#gmail.com";
Meteor.users.update({
_id: newUserId
}, {
$set: {
"services": {
servicesUserData
}
}
});

MongoDB _id as a String (MEAN Stack)

TL;DR - I am trying to use a collected value from a form input as a document _id but am getting a 404.
I've got a modal that opens and collects form data. My first input in the form is:
<input type="text" id="name" name="name" data-ng-model="name" />
When I try to modify the Mongo (Mongoose) model, to use name as the _id, the form wont post. I get a 404 from http://sitegoeshere/#!/somethings/whatever_i_type_in_for_name
Example model:
var SomethingSchema = new Schema({
_id: {
type: String,
default: 'default',
trim: true
}
}
mongoose.model('Something', SomethingSchema);
And in my Angular controller:
$scope.create = function() {
// Create new Something object
var something = new Somethings ({
_id: this.name
});
// Redirect after save
something.$save(function(response) {
$location.path('somethings/' + response._id);
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
I've been told that MongoDB allows Strings as the _id type so what gives? Any ideas?
UPDATE: Here's something strange, too. I wanted to see if maybe this was a limitation or bug of Mongoose so I got into the database and created two documents:
> db.subnets.find().pretty()
{ "_id" : ObjectId("546bef63395b0694d51b5cbe"), "description" : "description!" }
{ "_id" : "mystring", "description" : "more description!" }
When I go to my app and try to pull their individual views up, I can see the data for my custom _id document but get a 500 Internal Server Error when I try to access the other.
GET http://localhost:3000/somethings/546bef63395b0694d51b5cbe 500 (Internal Server Error)
GET http://localhost:3000/somethings/mystring 200 OK
The problem is most likely with this.name - looks like it's undefined.

an error about tailable cursor for a query in mongoose

User model contian SubscriptionSchema and AccessToken Schema, I had defined this two plugin schemas with {capped : 234556} too.
var User = new Schema({
email : String
, firstName : String
, password : String
, isAdmin : Boolean
, lastSeen : Date
, subscriptions : [ SubscriptionSchema ]
, accessTokens : [ AccessToken ]
}, {
toObject : { virtuals : true }
, toJSON : { virtuals : true }
, capped : 234556
});
var streamTest = User.find().limit(1).tailable().stream();
When I try to run the above code, I still get the error:
MongoError: tailable cursor requested on non capped collection
That doesn't look like a correct usage of a capped collection or tailable stream. But perhaps a little code first to demonstrate a working example:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
var userSchema = new Schema({
email: String,
},{
capped: 2048
});
var User = mongoose.model( "User", userSchema );
mongoose.connect('mongodb://localhost/atest');
var stream;
async.waterfall(
[
function(callback) {
var user = new User({ email: "existing" });
user.save(function(err,doc) {
if (err) throw err;
callback();
});
},
function(callback) {
User.find({}).sort({ "$natural": -1 }).limit(1).exec(function(err,docs) {
if (err) throw err;
console.log( docs );
callback(err,docs[0]);
});
},
function(doc,callback) {
stream = User.find({ "_id": { "$gt": doc._id } }).tailable().stream();
stream.on("data",function(doc) {
console.log( "Streamed:\n%s", doc );
});
callback();
},
function(callback) {
async.eachSeries(
['one','two','three'],
function(item,callback) {
var user = new User({ email: item });
user.save(function(err,doc) {
if (err) throw err;
console.log( "Saved:\n%s", doc );
callback();
});
},
function(err) {
if (err) throw err;
callback();
}
);
}
]
);
First things first, there really needs to be something in the capped collection for anything to work. This presumes that the collection does not exist and it is going to be initialized as a capped collection. Then the first step is making sure something is there.
Generally when you want to "tail", you just want the new documents that are inserted to appear. So before setting up the tailable cursor you want to find the "last" document in the collection.
When you know the last document in the collection, the "tailable stream" is set up to look for anything that is "greater than" that document, which are the new documents. If you did not do this, your first "data" event on the stream would empty all of the current collection items. So the options to .sort() and .limit() here do not apply. Tailing cursors initialize and "follow".
Now that the streaming interface is set up and an listener established, you can add items to the stream. These will then log accordingly, yet as this is "evented", there is no particular sequence to the logging here as either the "save" or the "stream" data event may actually fire first.
Now onto your implementation. These two lines stand out:
, subscriptions : [ SubscriptionSchema ]
, accessTokens : [ AccessToken ]
Those contain embedded arrays, they are not "external" documents in another collection, even though it would not matter if it even did.The general problem here is that you are (at least in some way) introducing an array, which seems to imply some concept of "growth".
Unless your intention is to never "grow" these arrays and only ever insert the content with the new document and never update it, then this will cause problems with capped collections.
Documents in capped collections cannot "grow" beyond their initial allocated size. Trying to update where this happens will result in errors. If you think you are going to be smart about it and "pad" your documents, then this is likely to fail when replicated secondary hosts "re-sync". All documented with capped collections.

No results retrieving document by UUID in MongoDB

I am trying to retrieve a document from MongoDB. The document has the field "ownerId" that contain a binary UUID. Using the Mongo console if I launch the command
db.dataset.find({ownerId: BinData(3,"ZQ6EAOKbQdSnFkRmVUUAAA==")}).pretty()
it returns:
{
"_id" : BinData(3,"VQ6EAOKbQdSnFkRmVUUAAA=="),
"name" : "Twitter",
"objectType" : "Tweet",
"ownerId" : BinData(3,"ZQ6EAOKbQdSnFkRmVUUAAA==")
}
When I try to retrieve the document from my node.js program, it fails and does not return any document.
My program is:
var mongo = require('mongoskin');
var db = mongo.db("mongodb://192.168.1.100:27017/test", {native_parser:true});
function HexToBase64(g) {
...
}
var uuidstr = "650e8400e29b41d4a716446655450000";
console.info(uuidstr);
base64str = HexToBase64(uuidstr);
console.info(base64str);
db.collection('dataset').find( { ownerId:new mongo.Binary(base64str, 4) } ).toArray(function (err, items) {
if(err) {
var msg = "Error getting 'dataset' objects from database.";
console.info(msg + " " + err);
return;
}
console.info("OK");
console.info(items);
});
The output is:
650e8400e29b41d4a716446655450000
ZQ6EAOKbQdSnFkRmVUUAAA==
OK
[]
What am I doing wrong?
Firstly, since you're going to query the collection by OwnerId, I'd suggest to create an index there. You can achieve that in mongoskin easily enough:
// Create and index by ownerId
db.collection('dataset').ensureIndex([['ownerId', 1]], true, function(err, res) {
if (err) throw err;
});
Once you've done that, you can now do things like this:
db.collection('dataset').findOne({ ownerId: 'some-uuid' }, callback);
Further, if it's the ObjectId type you're after, I'd recommend you use the provided helper (see this other question) to achieve that:
var ownerId = mongoskin.ObjectID(uuidstr);
Otherwise, I'd go with a different approach, perhaps using node-uuid :
var uuid = require('node-uuid');
var ownerId = uuid.v4();
db.collection('dataset').findOne({ ownerId: ownerId }, callback);
Hope this helps,

Categories