Create mongoose schema and insert document - javascript

I'm new to mongo and mongoose. I need to create schema from this object
trailers: [
{
id: 310131,
results: [
{
id: "564b9086c3a3686026004542",
iso_639_1: "en",
key: "gy_-pupKvxg",
name: "The Witch Official Trailer 1 2016 HD",
site: "YouTube",
size: 1080,
type: "Trailer"
},
{
id: "56aab2b19251417e110008b2",
iso_639_1: "en",
key: "feRupW34rUU",
name: "Trailer 2",
site: "YouTube",
size: 1080,
type: "Trailer"
}
]
}
],
Here is how I am doing it at the moment
// My Schema
var movieSchema = new mongoose.Schema({
....
...
..
.,
trailers : [
{
id: Number,
results : [
{
id: String,
iso_639_1: String,
key: String,
name: String,
site: String,
size: Number,
type: String,
}
],
_id : false
}
],
....
..
.
});
var Movie = mongoose.model('Movies', movieSchema);
// Insert movie into schema and save to database
movies.forEach(function(m) {
var movie = new Movie({
....
...
..
.,
trailers : m.trailers ? m.trailers : "",
....
...
..
.
});
movie.save(function(err) {
if(err) console.log('Error on save' + err);
});
}, this);
But I am doing it wrong can anyone spot or tell me how to insert each movie into schema object. Thanks in advance.

Per mongoose subdoc, please try to use .push to push trailers to movies. Here are the sample codes.
movies.forEach(function(m) {
var movie = new Movie({
....
//trailers : m.trailers ? m.trailers : "",
....
});
m.trailers.forEach(function(t){
movie.trailers.push(t);
});
movie.save(function(err) {
if(err) console.log('Error on save' + err);
});
});

According to me this should be your schema :
var movieSchema = new mongoose.Schema({
trailers: [
....
........
....
_id: Number,
results: [{
iso_639_1: String,
key: String,
name: String,
site: String,
size: String,
type: String
}]
........
....
]
});
Looking at your object, what I suggest is :
You should assign the _id field of the trailers array the Number that you currently assign to id field. And remove the id field from the schema.
_id field uniquely identifies a document inside a collection. So you should use it instead of id field that you created.
Secondly, you should let MongoDB create an _id field for your results array objects. That's why I haven't included an _id field in the results array object.
Next, to create new documents and save them in your collection, use your logic :
var Movie = mongoose.model('Movies', movieSchema);
// Insert movie into schema and save to database
movies.forEach(function(m) {
var movie = new Movie({
....
...
..
.,
(m.trailers) ? trailers = m.trailers : trailers = null,
....
...
..
.
});
movie.save(function(err) {
if(err) console.log('Error on save' + err);
});
}, this);
What's wrong with your logic is that you're trying to use ternary operator to check if m.trailers exist and if it does, you want to assign it to trailers array, and null otherwise. What you are using is :
trailers : m.trailers ? m.trailers : "",
What you should be using instead is :
(m.trailers) ? trailers = m.trailers : trailers = null,
Please do check it and let me know if it works.

Related

Editing a value of an object in an array

I have this object:
{
"_id" : ObjectId("5a8d83d5d5048f1c9ae877a8"),
"websites" : [
"",
"",
""
],
"keys" : [
{
"_id" : ObjectId("5a8d83d5d5048f1c9ae877af"),
"name" : "Google",
"value" : ""
},
{
"_id" : ObjectId("5a8d83d5d5048f1c9ae877ae"),
"name" : "Built With",
"value" : ""
},
{
"_id" : ObjectId("5a8d83d5d5048f1c9ae877ad"),
"name" : "Check Host",
"value" : ""
},
{
"_id" : ObjectId("5a8d83d5d5048f1c9ae877ac"),
"name" : "Alexa",
"value" : ""
},
{
"_id" : ObjectId("5a8d83d5d5048f1c9ae877ab"),
"name" : "Facebook",
"value" : ""
},
{
"_id" : ObjectId("5a8d83d5d5048f1c9ae877aa"),
"name" : "Instagram",
"value" : ""
},
{
"_id" : ObjectId("5a8d83d5d5048f1c9ae877a9"),
"name" : "Moz",
"value" : ""
}
],
"username" : "admin#admin",
"isPremium" : false,
"accType" : "admin",
"hash" : "very long hash",
"salt" : "long salt",
}
Now. Using NodeExpress and Mongoose I need to be able to edit the value field inside of every object inside the keys array.
My GET operation is this:
// GET: /websites/:_id - show edit form
router.get('/keys/edit/:_id', isAdmin, function(req, res, next) {
// console.log('tada');
// console.log(req.params._id);
Account.findOne({ _id: req.user._id }, function(err, user) {
var selectedKey = findById(user.keys, req.params._id);
// var keys = user.keys.findOne(req.params._id);
console.log(selectedKey);
res.render('admin/edit', {
title: 'Edit websites',
user: req.user,
value: selectedKey.value,
});
});
});
How the app works is: The admin logs in. He sees all users and chooses which one he wants to modify, then admin sees all keys. I will attach screenshots to explain it more clearly.
Now. I think I know what I need to do, but I have no clue how to translate it to code.
I think I need to: Find the index of the array element, like in the GET request, update the value with the posted value. I think I need to find the index in the array.
But as I said I have no clue how to do it.
My POST looks like this right now:
// POST: /keys/edit/_id - save updates
router.post('/keys/edit/:_id', isAdmin, function(req, res, next) {
var p = req.params;
var b = req.body;
Account.findOne({ _id: req.user._id }, function(err, user) {
var selectedKey = findById(user.keys, req.params._id);
// console.log('Key value: ' + req.body.keyValue);
// console.log('Selected key: ' + selectedKey);
console.log('id:' + req.params._id);
if (err) {
console.log(err);
} else {
console.log(user);
user.keys.set(req.params._id, req.body.keyValue);
user.save(err => {
if (err) {
console.log(err);
} else {
console.log('all good');
}
res.redirect('/admin');
});
}
});
EDIT: So I was working on it for a while now and I figured out this. I am using the correct user, I am grabbing the keys array inside, but I don't know how to find the id of the object in the array, which (object) I need to edit.
There is a lot of nesting and this might cause some issues.
EDIT 2: I'm attacking my account model. Forgot about it earlier. Sorry.
var mongoose = require('mongoose');
var website = require('./website');
var plm = require('passport-local-mongoose');
var accountSchema = new mongoose.Schema({
isPremium: Boolean,
accType: String,
websites: [],
keys: [
{ name: String, value: String },
{ name: String, value: String },
{ name: String, value: String },
{ name: String, value: String },
{ name: String, value: String },
{ name: String, value: String },
{ name: String, value: String },
],
});
accountSchema.plugin(plm);
module.exports = mongoose.model('Account', accountSchema);
You can perform the update atomically using $positional operator.
You include the field (_id) from the keys to locate the index of element and replace the placeholder($) with the found index from query part in the update part to set the value in keys.
router.post('/keys/edit/:_id', isAdmin, function(req, res, next) {
var p = req.params;
var b = req.body;
Account.findOneAndUpdate(
{_id: req.user._id,'keys._id':req.params._id },
{$set:{'keys.$.value':req.body.keyValue}},
{new: true},
function(err, account) {}
);
The question isn't entirely clear to me what you're looking to do, but what I can infer is that you want to do the following:
You have some object that has an Array of keys that has the following shape:
{
"_id" : ObjectId("5a8d83d5d5048f1c9ae877af"),
"name" : "Google",
"value" : ""
}
Judging from your sample object, I'm inferring the schema is defined something like:
const mongoose = require('mongoose')
const definition = {
websites: [String],
keys: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Key'
}]
}
const accountSchema = new mongoose.Schema(definition)
module.exports = mongoose.model('Account', topicSchema)
By the looks of the route, you want to update/edit that object at the given index: keys[i]. If this is the case, then there is no need to manually traverse the array, update the model directly:
const Key = require('./path/to/models/Key')
router.post('/keys/edit/:id', async (req, res) => {
const { keyValue } = req.body
const conditions = { _id: req.params.id }
await Key.findOneAndUpdate({ id }, { value: keyValue }).exec()
res.status(201).json()
})
The item in the array will be updated when you query the parent model.

MongoError: E11000 duplicate key error collection with passport

I have the following userSchema
var mongoose = require("mongoose"),
passportLocalMongoose = require("passport-local-mongoose");
var userSchema = new mongoose.Schema({
email: String,
password: String,
userName: String,
fname: String,
lname: String,
userType: Number,
subscribedThreads: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Threads"
}
]
});
// add passport methods
userSchema.plugin(passportLocalMongoose);
// export modules to be used by the file requiring it
module.exports = mongoose.model("Users",userSchema);
The first entry into the collection occurs as it should but the next ones give
{ [MongoError: E11000 duplicate key error collection: KManV3.users
index: username_1 dup key: { : null }]
name: 'MongoError',
message: 'E11000 duplicate key error collection: KManV3.users index:
username_1 dup key: { : null }',
driver: true,
code: 11000,
index: 0,
errmsg: 'E11000 duplicate key error collection: KManV3.users index:
username_1 dup key: { : null }',
getOperation: [Function],
toJSON: [Function],
toString: [Function]
}
Also, dbname.users.getIndexes() gives:
> db.users.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "KManV3.users"
},
{
"v" : 1,
"key" : {
"password" : 1
},
"name" : "password_1",
"ns" : "KManV3.users",
"background" : true
},
{
"v" : 1,
"unique" : true,
"key" : {
"username" : 1
},
"name" : "username_1",
"ns" : "KManV3.users",
"background" : true
}
]
Apparently every property of schema has been set as unique and I can't add data into collections even if the data is totally different. I'm not sure if it's due to integration of passport.
Looking at the options for passport-local-mongoose:
usernameField: specifies the field name that holds the username. Defaults to 'username'.
usernameUnique : specifies if the username field should be enforced to be unique by a mongodb index or not. Defaults to true.
Which explains why your collection has a unique index on the (non-existent-in-your-schema) username field.
If you don't actually set this field in documents that you add to the database, MongoDB will use null, and once the first document has been inserted, a subsequent document (also with the field value null for username) will throw an E11000 error.
So first, remove the index on username (and also password, I assume you once marked that field as unique in your schema), and set the proper field name for passport-local-mongoose to use:
userSchema.plugin(passportLocalMongoose, { usernameField : 'userName' });
(or email, if you want that field to be used as unique user identifier)
Error reason - The index is not present in your collection, in which you are trying to insert.
Solution - drop that collection and run your program again.

MongoDB index search works in console, but not from browser

All of this was working yesterday so I'm really not sure whats wrong. I'v searched on SO and been through the docs and steps a number of times but I havnt got it to work. Any help much appreciated as always!
If I type db.movies.find({ '$text': { '$search': 'elephant' } }) into the shell, it returns a list of titles with 'elephant' in the title. But if I run the same search from my browser it crashes the node server and I get MongoError: text index required for $text query.
The error comes from the error response from the find():
Movie.find(
{ '$text': { '$search': 'elephants' } },
(err, movies) => {
if (err) throw err; // MongoError: text index required for $text query
if (!movies) {
res.json({
data: null,
success: false,
message: 'No movies data'
});
} else {
res.json({
success: true,
data: movies
});
}
})
The index on my DB looks like this:
{
"v" : 2,
"key" : {
"_fts" : "text",
"_ftsx" : 1
},
"name" : "title_text",
"ns" : "db.movies",
"weights" : {
"title" : 1
},
"default_language" : "english",
"language_override" : "language",
"textIndexVersion" : 3
}
I also have mongoose schemas defined and I'm using an auto increment plugin to increment a custom id field on each movie save. (Saving movies works, so I am connecting to the DB ok)
mongoose.model('Job', new Schema({
id: Number,
title: String,
desc: String,
genre: String
})
.index({ title: 'text' })
.plugin(autoIncrement.mongoosePlugin));
As pointed out in the comments by #Chris Satchell
Adding the index to the mongoose schema solves this.
instead of:
mongoose.model('Job', new Schema({
id: Number,
title: String,
desc: String,
genre: String
})
do this:
mongoose.model('Job', new Schema({
id: Number,
title: { type: String, text: true },
desc: String,
genre: String
})
even though I still had .index({ title: 'text' }) on the Schema, you still need to define the { type: String, text: true } on the property.

Mongodb: Can't append to array using string field name

i am trying to push inside a subarray using $push but got a Mongo error, and not able to get through this after considerable search on google, and findOneAndUpdate didn't worked out so i used find and update separately
{ [MongoError: can't append to array using string field name: to]
name: 'MongoError',
err: 'can\'t append to array using string field name: to',
code: 13048,
n: 0,
lastOp: { _bsontype: 'Timestamp', low_: 2, high_: 1418993115 },
Schema:
var NetworkSchema = new Schema({
UserID: {
type: Schema.Types.ObjectId,
ref: 'User'
},
NetworkList: [{
type: Schema.Types.ObjectId,
ref: 'User'
}],
NetworkRequest: [{
from: [{
type:Schema.Types.ObjectId,
ref: 'User'
}],
to: [{
type: Schema.Types.ObjectId,
ref: 'User'
}]
}]
});
Document:
{
"UserID" : ObjectId("549416c9cbe0e42c1adb42b5"),
"_id" : ObjectId("549416c9cbe0e42c1adb42b6"),
"NetworkRequest" : [
{
"from" : [],
"to" : []
}
],
"NetworkList" : [],
"__v" : 0
}
Controller:
exports.update = function(req,res) {
var network = req.network;
var query={'UserID':req.body.UserID};
var update = {$push:{'NetworkRequest.to': req.body.FriendID}};
Network.find(query,function(err){
if (err) {
console.log(err);
return err;
} else {
}
});
Network.update(query,update,{upsert:true},function(err,user){
console.log(user);
if (err) {
console.log(err);
return err;
} else {
console.log('User'+user);
}
});
};
Everything #cbass said in his answer is correct, but since you don't have a unique identifier in your NetworkRequest element to target, you need to do it by position:
var query = {'UserID': req.body.UserID};
var update = {$push:{'NetworkRequest.0.to': req.body.FriendID}};
Test.update(query, update, {upsert: true}, function(err, result) { ... });
'NetworkRequest.0.to' identifies the to field of the first element of the NetworkRequest array.
Your query var query={'UserID':req.body.UserID}; identifies the document you want to edit. Then you need another query to identify which object in the NetworkRequest array that the UserID should be pushed into. Something like below:
var query = {
'UserID':req.body.UserID,
'NetworkRequest._id': ObjectId(someNetworkRequestId)
};
Then use this update query containing $ which is the index of the object in the nested array(NetworkRequest)
var update = {
$push:{
'NetworkRequest.$.to': req.body.FriendID
}
};

compound index not working?

I am trying to create a compound index using mongoose:
var ProjectSchema = new mongoose.Schema({
name: {type: String, required: true},
user: {type: mongoose.Schema.ObjectId, ref: 'User', required: true}
});
ProjectSchema.index({user: 1, name: 1}, {unique: true});
after that I dropped the old database in mongo
db.dropDatabase()
but I still can insert multiple documents with the same name and user id. why?
the index that it created shows in mongo as
> db.projects.getIndexes();
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "mydatabase.projects",
"name" : "_id_"
}
]
This is the pure mongo console function and it works,
Click Here for more detail. This is not descibe in mongoose's API.
I think it might be work.
db.collection.ensureIndex( { a: 1 }, { unique: true, dropDups: true } )
Actually your index does not appear to have been created. You are showing just the default primary key. Your output from .getIndexes() should be more like:
> db.projects.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "project.projects",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"user" : 1,
"name" : 1
},
"unique" : true,
"ns" : "project.projects",
"name" : "user_1_name_1",
"background" : true,
"safe" : null
}
]
There might be something up in your code, but this works for me:
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/project');
var db = mongoose.connection;
var Schema = mongoose.Schema;
var UserSchema = new Schema({
name: { type: String, required: true },
info: String
});
var ProjectSchema = new Schema({
name: { type: String, required: true},
user: { type: Schema.ObjectId, ref: 'User', required: 'true'}
});
ProjectSchema.index({ user: 1, name: 1}, { unique: true });
var User = mongoose.model( "User", UserSchema );
var Project = mongoose.model( "Project", ProjectSchema );
var user = new User({ name: "me" });
user.save(function(){
var project = new Project({ name: "Project1", user: user._id });
project.save(function(err, project, numAffected){
if (err) { // Should be fine
console.log(err);
}
console.log("First project created");
User.findOne({}).exec(function(err, user) {
console.log(user._id);
var project = new Project({ name: "Project1", user: user._id });
project.save(function(err, project, numAffected){
if (err) {
console.log(err); // Expect a problem here
}
console.log({ project: project, num: numAffected });
});
});
});
});
I had the exact same problem and this Github issue explained what was happening.
Firstly, compound indexes are only created after ensureIndex() is called. The problem for me is that I was using an import script that would drop my database and re-create it. ensureIndex() is not called until the server is restarted, so the compound index was not re-created after this.
The solution for me was to not drop my database in my import script, but instead iterate through my models and remove all the documents. That way the data was destroyed, but the indexes remained and hence the compound index would work.
I just had this problem, the compound index was not created at startup and I was checking the mongo logs, I could see that it was starting the build of the index but nothing was created, no errors etc...
Then I tried to manually create the index - in mongo console - and here I got an error (duplicate error in my case), so I removed the duplicates and I was able to create the index. I don't know why this was not popping up on my mongo logs.
Mongo v4

Categories

Resources