Missing subdocument while trying to fetch a document - node.js

Issue:
I am creating an accounts table with the schema as shown below. I have just one account document for a user in a mongo server that's running in my localhost. After defining the schema and adding a single account document, I wrote an endpoint to query and fetch that document (Model.find(id: '12345')) using the id key. The resulting JSON document has all the data except the subdocument named accRef as show in the Schema below. When I try the same find query using the Mongo Shell, I get the results perfectly. I've been trying to find what's causing this for almost an entire day now, without making much headway. Any help would be highly appreciated.
I started with an empty schema and added each field one by one, starting with the id attribute and fire the find query. Every single time, I get all the 75+ elements and subdocuments, but the moment I add the accRef subdoc to my schema, this piece of info disappears from the result.
Is there a limitation to the number of subdocuments that can be defined in mongoose's schema?
Also, I cannot seem to insert/save any new account object using the same schema as shown below. However, I can perform this insert/save operation using the very same JSON object, using a client like MongoChef.
Here's my JS module where I've defined my schema:
import mongoose from 'mongoose';
mongoose.connect('mongodb://localhost:27017/accounts');
const Schema = mongoose.Schema;
const accountsSchema = new Schema({
_id: Schema.ObjectId,
id: String,
uuid: String,
firstName: String,
lastName: String,
contactNumber: Number,
dob: Date,
email: String,
originalEmail: {type: String, index: true},
password: String,
socialMedia: {
facebook: {
id: String,
email: String,
token: String
}
},
domainInfo: {
country: String,
currency: String,
lang: String,
domain: String
},
profile: {
type: Number,
id: Number,
points: Number,
accumulated: Number
},
perks: {
id: Number,
type: Number
},
address: {
address: String,
postalCode: String
},
paymentInfo: {
cardNumber: String,
isValidCard: Number,
paypal: {
email: String
},
bank: {
bankName: String,
bankNumber: String,
accontId: Number,
accountHolderName: String,
bankBranchCode: String,
paymentTypeId: Number
},
dateCreated: {type: Date, default: Date.now},
dateModified: {type: Date, default: Date.now},
createdAt: {type: Date, default: Date.now},
updatedAt: {type: Date, default: Date.now}
},
metadata: {
timezone: String,
ipAddress: String,
signupMeta: String,
clientUserAgent: String,
signupUrl: String
},
accRef: {
type: String,
code: String,
url: String
},
key: String,
parentId: String,
type: String,
utm: String,
bounced: Number,
status: Number,
isPoints: Number,
isAdmin: String,
dateTutorialCompleted: {type: Date, default: Date.now},
dateCreated: {type: Date, default: Date.now},
dateModified: {type: Date, default: Date.now},
dateAccessed: {type: Date, default: Date.now},
dateVerified: {type: Date, default: Date.now},
datePurchased: Date,
createdAt: {type: Date, default: Date.now},
updatedAt: {type: Date, default: Date.now}
});
const Account = mongoose.model('Account', accountsSchema);
export default Account;
The function in the service class that fires the mongo query:
import Account from '../../models/mongo';
const getAccountById = (accountId) => {
return Account.find({id: accountId})
.then(response => {
if(response.length === 0) {
throw new Error("Account Not Found");
}
console.log(response);
return response;
})
.catch(error => {
throw new Error(error.message);
});
};
Mongoose Version tried with: 4.7.7 and 4.7.8 (tried both)
MongoDB Version tried with: 3.2 and 3.4 (tried both)
Node Version: 7.4.0

Related

How to query and get documents from two collections on mongoose

I need to query documents from two collections together on mongoose.
I am familiar with SQL query and but not familiar with mongoDB.
I have two schema for Users, Messages like following.
Users
const UserSchema = new mongoose.Schema({
name: String,
email: {type: String, unique: true},
password: String,
avatar: {type: String, default: ""},
created_at: { type: Date, default: Date.now() }
});
module.exports = mongoose.model('User', UserSchema);
Messages
const MessageSchema = new mongoose.Schema({
message: { type: String, default: "" },
from: { type: String, default: "" },
to: { type: String: default: "" },
is_read: { type: Boolean, default: false },
channel: { type: String, default: ''},
created_at: { type: Date, required: true, default: Date.now }
});
module.exports = mongoose.model('Message', MessageSchema);
I need to get messages with "is_read" is "false".
I want to get "user name" and "avatar" together.
The "from" value of message should be matched with "_id" of User.
I think this post sums it up well: Mongoose - query to get data from multiple collections
Specifically the second upvoted answer mentions similarities between sql and mongodb, and goes on to explain how to link collections in mongoose queries.

Node js and mongoose schema date.now code not working properly

I have created this schema for user registration:
let userSchema = new mongoose.Schema({
lname: String,
fname: String,
username: String,
email: String,
password: String,
registrationDate: {
type: Date,
default: Date.now()
},
referedBy: {
type: String,
default: ''
},
referalEnd: {
type: Date,
default: Date.now() + 5*365*24*60*60*1000
},
userRefererId: {
type: String,
default: uniqid()
}
});
As you can see, there is a Date.now function and uniqid function in the schema.
Those functions can be used approximately once every 5 minutes,
because if I create two users a few seconds apart, it generates the same uniqid and shows the same date.
Remove the () from Date.now() and just call Date.now.
I've run into this before, the schema is generated at deployment / start time and not regenerated on each new creation hence why the time is always the same. Its better to generate the date / time outside the new Model().save() call.
let userSchema = new mongoose.Schema({
lname: String,
fname:String,
username: String,
email: String,
password: String,
registrationDate: {
type: Date,
default: function(){return Date.now()}
},
referedBy: {
type:String,
default: ''
},
referalEnd: {
type: Date,
default: function(){ return Date.now() + 5*365*24*60*60*1000}
},
userRefererId: {
type:String,
default: uniqid()
}
});

How to have relate two collections that have a one-to-one relationship

I have 0 experience with NoSQL databases and it is hard to not come up with a "SQL solution" to this problem. I have a Restaurant, which obviously has an address. My first idea was to simply put a lot of fields such as country, city, zip, line1, etc... However I thought that referencing it to an Address document, giving me the flexibility to easily change the structure of Addresses, so after a little bit of research I came up with this:
var RestaurantSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
address: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Address',
required: true
},
// a few more fields
createdAt: {type: Date, default: Date.now},
updatedAt: {type: Date, default: Date.now},
});
var AddressSchema = new mongoose.Schema({
restaurant: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Restaurant'
},
line1: {
type: String,
required: true
},
line2: {
type: String,
}
// etc
createdAt: {type: Date, default: Date.now},
updatedAt: {type: Date, default: Date.now},
});
My question comes after wondering how I would do if I wanted to retrieve all restaurants from a city, for example, I'd do something like find('Houston') and then get each Restaurant from each id referenced by the Addresses retrieved?
I feel like there's a better way to do this but at the moment I don't even know what else to search trying to find an answer.
You can make your address schema like this
var AddressSchema = new mongoose.Schema({
restaurant: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Restaurant'
},
city: {
type: String,
required: true
},
line1: {
type: String,
}
// etc
createdAt: {type: Date, default: Date.now},
updatedAt: {type: Date, default: Date.now},
});
Ques: how I would do if I wanted to retrieve all restaurants from a city?
Ans: For this you can use populate of moongose
Ex:
var addressModule=require('addressSchema')
addressModule.find({city:'Houston'}).populate({'path':'restaurant','model':'restaurantSchema'})
Result:
[
{
restaurant:{
name:"ABC",
address:"123"
},
city:"Houston",
line1:"xxx"
},
{
restaurant:{
name:"DEF",
address:"233"
},
city:"Houston",
line1:"xxx"
}
]

Mongoose: find all referenced documents

I have 2 schemas:
var pollSchema = new mongoose.Schema({
title: String,
created: {
type: Date, default: Date.now
},
options: [{
label: String,
count: {
type: Number, default: 0
},
backgroundColor: {
type: String, default: '#fff'
}
}],
author:{
id:{
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
}
});
var userSchema = new Schema({
username: {type: String, unique:true},
email: {type: String, unique:true, lowercase: true},
password: String
});
Now each poll will store data of it's author.
Questions:
How can I redesign my schemas - so I will be able to find all the polls belong to particular user?
Or should I leave the schemas the same and find another approach?
you can still find all the polls belonging to a particular user . You have the author.id for that.
Also you can keep an array as var userSchema = new Schema({
username: {type: String, unique:true},
email: {type: String, unique:true, lowercase: true},
password: String,
polls: []
});
And every time a user polls, push the userId inside the polls array, which you can later populate or get the count.

Schema Association in Mongoose

I have 2 models:
Here is the User Model:
const userSchema = new mongoose.Schema({
email: { type: String, unique: true, required: true },
password: { type: String, required: true },
passwordResetToken: String,
passwordResetExpires: Date,
facebook: String,
twitter: String,
tokens: Array,
profile: {
name: String,
gender: String,
location: String,
website: String,
picture: String
}
}, { timestamps: true });
And here is the Revive Model:
const reviveSchema = new mongoose.Schema({
reviveShowName: {type: String, required: true},
reviveTitle: {type: String, required: true},
reviveCategory: {type: String, required: true},
reviveGoal: {type: Number, required: true},
revivePhoto: {type: String, required: true},
reviveVideo: {type: String},
reviveStory: {type: String},
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
name: String
}
}, { timestamps: true });
In the Revive model, I'm trying to the reference the author and get the author's id and that works... How do I also get the name from profiles -> name...? Clearly name: String is wrong...
Mongoose relations work, based on the ref and type value of the nested object. In your case you have associated the id property of author to point to the User model.
If you want to populate the author with the user information, you should just do :
author: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
}
Then in your query you just use populate
Revive.find({})
.populate( 'author' )
.exec( function( error, docs ) {
console.log( docs ); // will have `[{author:{profile:{...}}}]` data
} );

Resources