How can I add a unique auto increment ID inside mongoDB object - mongodb

I have a table users. This is the schema.
var usersSchema = mongoose.Schema({
uname : {type : String , unique: true},
email : {type : String},
logintype : {type : String},
password : String,
status : String,
hash : String,
social: {},
games: Object,
os: String,
friends: Object,
msges:Object
});
The msges are objects. But what I want is to have key value pair inside msges. So what I did was
function sendMsgToFriend(uname,friendUname,title,msg,time,callback){
global.users.find({"uname":friendUname},
function(err,doc){
if(err){
callback(false,err,"Msg cannot be sent");
}else{
global.users.update( {"uname" : uname},
{
$addToSet : {
"msges":{time:{"from":uname,"title":title,"msg":msg,"read":false}}
}
},function(err,doc){
if(err){
callback(false,err,"Msg cannot be sent");
}else{
callback(true,null,"Msg has been sent");
}
}
);
}
}
);
}
I tried to make 'time' the key and rest its value. But what happened was that instead of value of time, string "time" appeared. Can I make an auto increment Key of msges? Thankyou in advance.

You define "msgs" as a object but what i read from your question is you want a array of objects..
Why don't you create a model for messages and make make "msgs" an array of references to that object.
var usersSchema = mongoose.Schema({
uname : {type : String , unique: true},
email : {type : String},
logintype : {type : String},
password : String,
status : String,
hash : String,
social: {},
games: Object,
os: String,
friends: Object,
msges: [{
message_id : { type: Schema.Types.ObjectId, ref: 'Message' },
read_on : Boolean }]
});
and a schema for the messages
var messageSchema = Schema({
from : String,
title: String,
msg : String,
send_on : Date
});
var Message = mongoose.model('Message', messageSchema);
This way all messages are in a collection and you can track the read status per user.
For retrieving the messages during user retriaval you can use mongoose populate
UPDATE:
if you don't want an xtra collection make your user schema something like:
var usersSchema = mongoose.Schema({
uname : {type : String , unique: true},
email : {type : String},
logintype : {type : String},
password : String,
status : String,
hash : String,
social: {},
games: Object,
os: String,
friends: Object,
msges: [{
id : Schema.Types.ObjectId,
from : String,
title: String,
msg : String,
send_on : Date,
read_on : Boolean }]
});
But keep in mind that if you also want the message to be present with the user who sended it you need to put it in the array by both users (keep id equal).... So you should think / talk about the best solution in your scenario.

Related

Mongoose find is returning a blank array, RoboMongo finds data

I've got an Express application which until this morning was returning an array of objects from the database. Now it's returning an empty array. RoboMongo shows me that the data is still there and doing fine. Any ideas?
My model:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const plotStatusSchema = new Schema(
{
recordDate: Date,
blockName: String,
growerName: String,
company: String,
variety: String,
planted: Number,
region: String,
yieldInKG: Number,
changeInPcnt: Number,
currentRipeness: String,
nextStage: String,
timeToNextInDays: Number,
status: Number
},
{ bufferCommands: false },
{ collection: 'plotStatuses' }
);
const ModelClass = mongoose.model(
'plotStatus',
plotStatusSchema,
'plotStatuses'
);
module.exports = ModelClass;
My returning controller:
const PlotStatus = require('../models/plotStatus');
const jsonpack = require('jsonpack');
exports.plotStatuses = async (req, res) => {
const plotStatus = await PlotStatus.find({
company: 'req.user.companyCode'
}).lean();
if (!plotStatus) {
throw new Error('Plot Statuses not found');
} else {
res.send(plotStatus);
}
};
A sample of my data:
{
"_id" : ObjectId,
"recordDate" : ISODate,
"blockName" : String,
"blockCode" : String,
"growerName" : String,
"company" : String,
"variety" : String,
"planted" : ISODate,
"region" : String,
"yieldInKG" : Number,
"changeInPcnt" : Number,
"currentRipeness" : String,
"nextStage" :String,
"timeToNextInDays" : Number,
"status" : Number,
"targetYieldInKG" : Number,
"currentStatePercentage" : Number,
"totalLengthOfPhase" : Number,
"nextPhaseStart" : ISODate,
"currentBrix" : Number,
"currentPh" : Number,
"currentTA" : Number,
"plotGeoJSON" : Object,
"historicalData" : Array
}
I know that the Schema no longer matches the shape of the JSON, but can I return all the JSONs that fit the find condition anyway?
You are searching the string "req.user.companyCode" inside the company attribute. Obviously, you don't have that company code in your data. Try it again without the quores:
const plotStatus = await PlotStatus.find({
company: req.user.companyCode
}).lean();

Fastest way to query collection for ALL documents

My collection has approximately 500 documents, which will be double that in a few weeks:
How can I make getting all the documents faster? I'm currently using db.registrations.find(), so that I can have all the documents available for searching, sorting, and filtering data. Using skip/limit makes the query display quickly, but you can't search all the registrations for players, and that's necessary.
My schema:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var playerSchema = new mongoose.Schema({
first: {
type: String,
required: true
},
last: {
type: String,
required: true
},
email: {
type: String,
required: true
},
phone: {
type: String,
required: true
},
address: {
address: String,
city: String,
state: String,
zip: String,
country: {
type: String,
"default" : "USA"
},
adult: Boolean
}
});
var registrationsSchema = new mongoose.Schema({
event : {
type: String,
required: true
},
day : {
type: String,
required: true
},
group : {
type: String,
required: true
},
field : {
type: String,
},
price : {
type: Number,
required: true
},
players : [playerSchema],
net : Number,
team : {
type: Number,
min: 0,
max: 7,
"default" : null
},
notes: String,
paymentID : {
type: String,
required: true,
"default": "VOLUNTEER"
},
paymentStatus : {
type: String,
"default" : "PAID"
},
paymentNote : String,
// users : [userSchema],
active : {
type: Boolean,
default: true
},
users: [{
type: Schema.Types.ObjectId,
ref: 'User'
}],
createdOn : {
type : Date,
"default" : Date.now
},
updatedLast : {
type: Date
}
});
mongoose.model('Registration', registrationsSchema);
There is no big deal to load 1000 records from mongodb using mongoose. I did it in the past (2-3k records) and it worked well as long as I respected this 2 rules:
Don't load all the mongoose stuff
Use lean query.
This way it won't load all the mongoose methods / attributes and it will get just the data of your objects. You can't use .save() or other methods but it's way faster to load.
Use stream to load your data.
Streams are a good way to load large dataset with nodejs/mongoose. It will read the data block by block from mongodb and send them to your application for usage. You will avoid the tipical case :
I wait 2 seconds my data and my server is idle
My server is 100% CPU during 2 seconds to process the data I got and the db is idle.
With streams, in this example your total time will be ~2s instead of 2+2=4s
To load data from stream with mongoose use the .cursor() function to change your request to a nodejs stream.
Here is an example to load all your players fast
const allPlayers = [];
const cursor = Player.find({}).lean().cursor();
cursor.on('data', function(player) { allPlayers.push(player); });
cursor.on('end', function() { console.log('All players are loaded here'); });
You can achieve your objective using the following ways.
By default if you query for mongoose document, it will load with all of it's attributes and other necessary meta-data required(ie.,with lean = false). so if you use lean() function, it will load only a plain java script objects and it won't return even setter and corresponding getter methods. So that you can get all the documents very very fast. And you will get High performance. that's what the magic of lean() function on the back ground.
Another suggestion is as a thumb rule, please maintain proper indexing as per your requirement for each collection to get good performance while querying.
Hope this will help you!

How can I select single column from MongoDB?

I have a users table of the following schema
var usersSchema = mongoose.Schema({
uname : {type : String , unique: true},
email : {type : String},
logintype : {type : String},
password : String,
status : String,
hash : String,
social: {},
games: Object,
os: String,
friends: Object,
msges:Object
});
I want to fetch msges of specific user. I have the username. Currently this is what I am doing
var getMessages = function(user){
global.users.find({"uname" : uname},
{"friends.friendUname":1,_id:0},
function(err,doc){
if(err){
callback(false,err,"",null);
}else{
callback(true,null,"",doc);
}
}
);
}
But I don't want all the fields. Any help?
it should be something like this
global.users.find({"uname" : uname}, 'msges -_id', function (err, doc) {
...
})

how to unwind in moongose after populate

I have two schemas, Mails and Users, as defined here:
var MailsSchema = new Schema({
from : [{ type: ObjectId, ref: 'UsersSchema' }],
to : [{ type: ObjectId, ref: 'UsersSchema' }],
date : { type: Date, default: Date.now },
subject : { type: String, default: '' },
message : { type: String, default: '' },
isRead : { type: Boolean, default: false }
});
var UsersSchema = new Schema({
username : String,
pass : String,
firstName : String,
lastName : String,
age : Number
});
I want to get list of mail that send to specific user, populate the username in 'from' field,
I tried to do it that way:
mails.find({ to: id }).populate('from', 'username').exec(function (err, docs)...
The problem is:
I'm getting an array in 'from' field, I want to get only the username.
I.e. instead of getting this result:
[{"_id":"53fa2902da480e4c0d315fcd","__v":0,"isRead":false,"message":"SABABA","subject":"MA KORE","date":"2014-08-24T18:03:46.428Z","to":["53f9dbe164b1375c1c5b997a"],"from":[{"_id":"53f9dbe164b1375c1c5b997a","username":"adaroh"}]}]
I want to get that result:
[{"_id":"53fa2902da480e4c0d315fcd","__v":0,"isRead":false,"message":"SABABA","subject":"MA KORE","date":"2014-08-24T18:03:46.428Z","to":["53f9dbe164b1375c1c5b997a"],"from":"adaroh"}]
That's just how populate works. You can modify the docs yourself to filter out the extra id. In your exec, for each doc that gets populated you can look at the from array and do
doc.from[i] = doc.from[i].username

Mongoose retrieval of info from multiple collections

I'm building a resume building app with Mongoose and Express. I set my models up so that education and work experience are both in their own collections. something similar to this:
"degree" : "BA",
"major" : "Econ",
"minor" : "Bus. Admin",
"startDate" : ISODate("2013-12-31T00:00:00Z"),
"endDate" : ISODate("2013-01-01T00:00:00Z"),
"user" : "example#gmail.com",
"created" : ISODate("2013-10-15T19:32:09.357Z"),
"_id" : ObjectId("525d9839ddc8bf7855000001"),
"school" : {
"name" : "university of alabama",
"loc" : "austin, tx"
},
"__v" : 0
I have a reference to the _id of the User model in the "user" value. my User model looks like so:
var schema = mongoose.Schema({
_id: {type: String, lowercase: true, trim: true, validate: validEmail }
, name: { first: String, last: String}
, salt: {type: String, required: true}
, hash: {type: String, required: true}
, edu: [{type: String, ref: 'Education'}] });
When I try to populate the edu section of my User model with information from the education model it's not finding anything.
My query is this:
var query = User.findById(user)
.populate('edu');
So how would I properly allow my User model make references to the education model so that I can send info from both to a view? Could I populate to fields like that?
Any advice would be mega helpful. I'll be scouring the docs, google and trying random things that kind of make sense in the mean time.
Thank you.
You need to use the mongoose.Schema.Types.ObjectId type in order for populate to work properly.
var schema = mongoose.Schema({
_id: {type: String, lowercase: true, trim: true, validate: validEmail }
, name: {first: String, last: String}
, salt: {type: String, required: true}
, hash: {type: String, required: true}
, edu: [{type: mongoose.Schema.Types.ObjectId, ref: 'Education'}] });
side note:
you don't need to define _id as you get that automatically and it should not be an email. Use a separate email field for that.