Mongo/mongoose unique works every other time - mongodb

I'm writing a subdomain string to a Mongodb database (run on Compose.io), and I need to ensure that the subdomain.name string is unique.
I setup my document as
var SubdomainModel = function() {
var subdomainSchema = mongoose.Schema({
name: {type: String, require: true, index: true, unique: true, lowercase: true, trim: true},
createdBy: {type: mongoose.Schema.Types.ObjectId, require: true, ref: 'User'}
});
subdomainSchema.pre('save', function(next) {
var subdomain = this;
subdomain.name = subdomain.name.toLowerCase();
next();
});
return mongoose.model('Subdomain', subdomainSchema);
}
module.exports = new SubdomainModel();
I'm using frisby.js to run my tests (it's based on jasmine). In my test, I delete the subdomain document, then create new subdomains.
I also timestamp the subdomain name so I can make sure it is unique. I create the subdomain, then wait 15 seconds and create it again and ensure that my 2nd create call fails.
The test passes one time, then I re-run and it fails the next. When I look in the db, sure enough, there are two entries for the same subdomain.
{ name: "test-1425876399170", _id: ObjectId("54fd25af5ce2db7c0a7192d1"), __v: 0 }
{ name: "test-1425876399170", _id: ObjectId("54fd25be5ce2db7c0a7192d3"), __v: 0 }
Maybe the problem is being caused by the db being blown away, I'm not sure, but I'm amazed at how consistently it fails/passes/fails/passes.
Any idea how to resolve this?

Related

Auto increment in postgres/sequelize

I have a Postgres database using Sequelize (node/express) as ORM. I have a table called students, in it there are columns: id and name.
In this students table, I have several registered students, but a detail: the last registered ID is 34550 and the first is 30000, they come from an import from a previous database, I need to continue counting from 34550, or that is, from the last registered student. However, when I register a student via API, the generated ID is below 30000. I know that in mysql the ID field being AUTO INCREMENT would solve it, however, as I understand it, postgres works in a different way.
How could I solve this problem?
The migration used to create the table is as follows:
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('students', {
id: {
type: Sequelize.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true,
},
name: {
type: Sequelize.STRING,
allowNull: false,
},
});
},
down: (queryInterface) => {
return queryInterface.dropTable('students');
},
};
Table print:
Based on Frank comment, I was able to adjust using:
SELECT setval('public.students_id_seq', 34550, true);

Express.js PUT Request not updating MongoDB

I'm working on a project that is basically a super watered down social media website.
I have a chunk done already, but I'm having some issues creating a put request to my mongodb. Basically, I want to send a put request to update a numeric value to be able to have a like counter on each post.
What I'm trying do here is send a put request with a specific post id. I'm storing the post id in a hidden text box to reference it. This is pug formatted HTML:
input.form-control(type='hidden' value=item.id id='postId' placeholder='' name='postId' required='false')
form(method='PUT' action='/update/{{post._id}}')
button(type='submit') Like
Then in my router.js file I'm basically trying to take in that id and set the likes field in the Post schema to 1 (just for testing).
router.put('/update/:id', function (req, res, next) {
let id = {
_id: ObjectID(req.params.id)
};
Post.update({_id: id}, {$set:{'likes': 1}}, (err, result) => {
if(err) {
throw err;
}
res.send('user updated sucessfully');
});
});
Here is my post schema
var mongoose = require("mongoose");
var PostSchema = new mongoose.Schema({
postText: {
type: String,
unique: false,
required: true,
trim: true
},
usernameText: {
type: String,
unique: false,
required: true,
trim: true
},
likes:{
type: Number,
unique: false,
required: false
}
});
var Post = mongoose.model("Posts", PostSchema);
module.exports = Post;
Any and all help would be highly appreciated, thank you
You can't change the ObjectId. The ObjectId is generated by MongoDB and can't be changed by the user using query functions.
If you want to assign a unique id to each user for example, then create a separate field in your schema.
You cannot change the ID
'PUT' method is not supported directly as far as I know. You need method override

MongoDB Mongoose save object with nested objects

I'm new to MongoDB and I'm creating a simple db with Mongoose with the following models: User, Game and Players.
So, one user contains none or many games. Every game has to players, and each player refers to a user. Like this (I simplified the schemas for clarity):
const UserSchema = new Schema({
name: String,
games: [{
type: Schema.Types.ObjectId,
ref: 'game'
}]
});
const GameSchema = new Schema({
mode: Number,
players: {
type: [{
type: Schema.Types.ObjectId,
ref: 'player'
}],
required: true
}
});
const PlayerSchema = new Schema({
order: Number,
isWinner: Boolean,
user: {
type: Schema.Types.ObjectId,
ref: 'user',
required: true
}
});
So, now in the frontend I want to send a petition to the backend to create a new game for users Joe (_id:11111) and Bob (_id:22222) and so I send a POST to /api/games with the body { users: [ 11111, 22222 ] }
Now my question is, for the backend to create a new game, it also has to create 2 players. What's the best way to achieve this?
In the Game.create() method, shall I retrieve the data, create and save the players, create the game, assign the players, save the game, and also update the users and add the game ids?
I also read about Mongoose middleware, where you can set certain functions to be executed before or after some operations. So maybe it's better:
pre function before Game.create, to create the players
post function before Game.create, to update the users
This last one seems cleaner.
What's the best way? Maybe another one I have not considered?
Thanks
I would suggest you using the post and pre functions defined in the mongoose middleware. They're pretty straightforward and neat to use. It will probably solve your problem.
Here is a personal example of a problem we had; In our case, we had to assign a userId from a sequence in the database. We used the following code:
var UserSchema = new Schema({
username: { type: String, required: true, unique: true },
id: { type: String },
...
});
UserSchema.pre('save', function(next) {
let doc = this;
let id = 'userSeq'
Sequence.findByIdAndUpdate(id, { $inc : {nextSId : 1} }, function(error,data) {
if(error)
next(error)
doc.id = data.nextSId-1;
next();
})
});
My suggestion is that before you create the game, you can search for the users and add a reference to the game. If I were you, I would use the findAndModify query of mongodb to find the users or create if they do not exist yet.

Can't update or query embedded sub-documents using MongoDB? Now what?

I took the NoSQL plunge against all my RDBMS prejudices from my past. But I trusted. Now I find myself 3 months into a project and the exact reasons we adhered to RDMS principles seem to be biting me in the butt. I think I just discovered here on stackoverflow that I can't work with twice embedded arrays. I followed the noSQL, embedded document approach like a good kool-aid drinker and feel like I've been betrayed. Before I swear off noSQL and go back and refactor my entire code-base to adhere to new 'normalized' model I'd like to here from some no-sql champions.
Here is my model using one big document with embedded docs and the works:
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
User = mongoose.model('User');
var Entry = new Schema({
text: String,
ups: Number,
downs: Number,
rankScore: Number,
posted: {
type: Date,
default: Date.now
},
postedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
});
var boardSchema = new Schema({
theme: String,
created: {
type: Date,
default: Date.now
},
owner: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
entered: {
type: Boolean,
default: false
},
entries: [Entry],
participants: [{
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User'},
date: { type: Date, default: Date.now },
topTen: [ { type: mongoose.Schema.Types.ObjectId, ref: 'Entry'} ]
}]
});
mongoose.model('Board', boardSchema);
Basically, I want to query the document by Board._id, then where participants.user == req.user.id, I'd like to add to the topTen[] array. Note participants[] is an array within the document and topTen is an array within participants[]. I've found other similar questions but I was pointed to a Jira item which doesn't look like it will be implemented to allow the use of $ positional operation in multiple embedded arrays. Is there no way to do this now? Or if anyone has a suggestion of how to model my document so that I don't have to go full re-write with a new normalized reference model...please help!
Here are some of my query attempts from what I could find online. Nothing worked for me.
Board.update({_id: ObjectId('56910eed15c4d50e0998a2c9'), 'participants.user._id': ObjectId('56437f6a142974240273d862')}, {$set:{'participants.0.topTen.$.entry': ObjectId('5692eafc64601ceb0b64269b') }}
I read you should avoid such 'nested' designs but with the embedded model its hard not to. Basically this statement says to me "don't embed" go "ref".

Mongoose populate() returning empty array

so I've been at it for like 4 hours, read the documentation several times, and still couldn't figure out my problem. I'm trying to do a simple populate() to my model.
I have a User model and Store model. The User has a favoriteStores array which contains the _id of stores. What I'm looking for is that this array will be populated with the Store details.
user.model
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var UserSchema = new Schema({
username: String,
name: {first: String, last: String},
favoriteStores: [{type: Schema.Types.ObjectId, ref: 'Store'}],
modifiedOn: {type: Date, default: Date.now},
createdOn: Date,
lastLogin: Date
});
UserSchema.statics.getFavoriteStores = function (userId, callback) {
this
.findById(userId)
.populate('favoriteStores')
.exec(function (err, stores) {
callback(err, stores);
});
}
And another file:
store.model
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var StoreSchema = new Schema({
name: String,
route: String,
tagline: String,
logo: String
});
module.exports = mongoose.model('Store', StoreSchema);
After running this what I get is:
{
"_id": "556dc40b44f14c0c252c5604",
"username": "adiv.rulez",
"__v": 0,
"modifiedOn": "2015-06-02T14:56:11.074Z",
"favoriteStores": [],
"name": {
"first": "Adiv",
"last": "Ohayon"
}
}
The favoriteStores is empty, even though when I just do a get of the stores without the populate it does display the _id of the store.
Any help is greatly appreciated! Thanks ;)
UPDATE
After using the deepPopulate plugin it magically fixed it. I guess the problem was with the nesting of the userSchema. Still not sure what the problem was exactly, but at least it's fixed.
I think this issue happens when schemas are defined across multiple files. To solve this, try call populate this way:
.populate({path: 'favoriteStores', model: 'Store'})