I'm trying to use meteor-collection2 to validate my collection.
I have a service, on server side :
Meteor.methods
UserSignUpService: (options) ->
# create user
Accounts.createUser options
That I call on client side :
Meteor.call 'UserSignUpService',
email: 'my.email#domain.com'
password: 'mypassword'
profile:
name: 'me'
And this is my schema :
# user profile
UserProfile = new SimpleSchema
name:
type: String
min: 1
max: 50
optional: false
# user
User = new SimpleSchema
emails:
type: [Object]
optional: false
"emails.$.address":
type: String
regEx: SimpleSchema.RegEx.Email
"emails.$.verified"
type: Boolean
createdAt:
type: Date
profile:
type: UserProfile
optional: false
services:
type: Object
optional: true
blackbox: true
# links to user collection
Meteor.users.attachSchema User
But, when user is created, there are not all fields in my mongo collection :
{ "_id" : "ikvBq95JBLXMCSnhT", "emails" : [ { "address" : "my.email#domain.com" } ] }
Whereas it should be :
{ "_id" : "WNkjGFhNkLpRR2Jex", "createdAt" : ISODate("2015-08-06T09:00:59.887Z"), "services" : { "password" : { "bcrypt" : "$2a$10$QvMLuI.Pv0bzzii3ZZP...fHfUlU9KiYfcsC2VHBf6q1OSPM6cfTW" }, "resume" : { "loginTokens" : [ { "when" : ISODate("2015-08-06T09:01:00.002Z"), "hashedToken" : "9KyqjRVSWm0nfIlS0sqODRmddlJ5GaG3mJ4+RMItOhk=" } ] } }, "emails" : [ { "address" : "my.email#domain.com", "verified" : false } ], "profile" : { "name" : "me" } }
Any idea on this problem ?
Many Thanks !
You're not actually setting the createdAt field value, try:
createdAt:
type: Date
autoValue: function(){
if this.isInsert return new Date()
else if this.isUpsert return { $setOnInsert: new Date };
else if this.isSet this.unset();
}
You can also omit optional: false in your schema since that's the default.
Also, and I suspect this is the bigger problem, not all user keys are returned to the client by default, only profile is normally published. For example you're expecting the services key but that doesn't normally come across. Look at the document in the mongo console and see what's there. You might need to publish a more comprehensive set of keys to the client.
Related
I have a problem regarding MongoDB, Mongoose, and Node.js.
I have this schema using Mongoose:
const EmoteSchema = new mongoose.Schema({
guild_id: String,
users: [{
user_id: String,
emotes: [{
emote: String,
channels: [String],
cooldown: Number,
all_channels: { type: Boolean, default: true },
global_cooldown: { type: Boolean, default: true },
lock: { type: Boolean, default: false }
}]
}]
});
What it looks like MongoDB:
{
"_id" : ObjectId("5ee6776b9277898982b0a25a"),
"guild_id" : "714931095929618443",
"users" : [
{
"_id" : ObjectId("5ee6776b9277898982b0a25b"),
"user_id" : "160230784257622016",
"emotes" : [
{
"channels" : [ ],
"all_channels" : true,
"global_cooldown" : true,
"lock" : false,
"_id" : ObjectId("5ee6776b9277898982b0a25c"),
"emote" : "🔤"
}
]
}
],
"__v" : 0
}
What I'm trying to achieve is to update the database, based on three conditions:
When sent the information of the guild_id, user_id, and emote:
If the guild_id, user_id, and emote exist in the database do nothing
If the guild_id, user_id (and emote does NOT exist), update the emote array with new emote
If the guild_id, (and user_id does not exist), update the users array with new user_id and update with the emote
If guild_id does not exit: create new entry with new guild_id, users array and emotes array
This is what I have attempted to do:
let filter = {
guild_id: guild_inp,
"users.user_id": user_inp
};
let update = {
$push: { "users.$[i].emotes": { emote: emote_inp } }
};
let options = {
arrayFilters: [
{ "i.users.user_id": user_inp }
],
rawResult: true
};
Emote.findOneAndUpdate(filter, update, options, fn);
If the guild_inp: 714931095929618443, user_inp: 160230784257622016, and emote:
The callback functions gets this result:
RES: {
lastErrorObject: { n: 1, updatedExisting: true },
value: {
_id: 5ee6776b9277898982b0a25a,
guild_id: '714931095929618443',
users: [ [Object] ],
__v: 0
},
ok: 1
}
It says that it has been updated? But I see no changes in MongoDB!
Any help is appreciated if there is an easier way to achieve what I am doing such as a new schema please share it!
It might be conceptual question about _id in mongodb.
I understand mongodb will insert a _id field automatically if you don't set key field in document.In my case, I defined a field as Object Array, I don't know why it always create a _id in each Object in Array of this field.
I do appreciate if someone could clarify it for me.
Mongoose Model Scheme definition:
module.exports = mongoose.model("Application", {
Name: String,
Description: String,
Dependency: [
{
App_id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Application'
},
Priority: Number
}
]
});
This is an Update operation, request data is:
{ _id: '571953e33f33c919d03381b5',
Name: 'A Test Utility (cmd)',
Description: 'A Test Utility (cmd)'
Dependency:
[ { App_id: '571953e33f33c919d03381b6', Priority: true },
{ App_id: '571953e33f33c919d03383da', Priority: 0 } ]
}
I use this code to update it
var id = req.body._id;
Application.findOneAndUpdate({ _id: id }, req.body, function (err, app) {
if (err)
res.send(err);
res.json(app);
});
The update is successful.But the document in mongodb is:
{
"_id" : ObjectId("571953e33f33c919d03381b5"),
"Name" : "A Test Utility (cmd)",
"Description" : "A Test Utility (cmd)",
"Dependency" : [
{
"Priority" : 1,
"App_id" : ObjectId("571953e33f33c919d03381b6"),
"_id" : ObjectId("571a7f552985372426509acb")
},
{
"Priority" : 0,
"App_id" : ObjectId("571953e33f33c919d03383da"),
"_id" : ObjectId("571a7f552985372426509aca")
}
]
}
I just don't understand how come the _id in the "Dependency" Array?
Thanks.
When you use [{..}] that means inside it act as a sub schema and you know that MongoDB insert a _id field automatically if you don't set key field in document. So you need to force to insert document without _id field.
Need use {_id:false} for your Dependency array schema to insert without _id
var ApplicationSchema = new mongoose.Schema({
Name: String,
Description: String,
Dependency: [
{
App_id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Application'
},
Priority: Number,
_id: false
}
]
});
module.exports = mongoose.model("Application", ApplicationSchema);
I'm using the following schema to store some user tokens which should expire after a certain amount of time (30 minutes in this case):
var Schema = require('mongoose').Schema;
var tokenSchema = mongoose.Schema({
email: { type: String, required: true, trim: true },
token: { type: String, required: true },
created: { type: Date, expires: 60*30, default: Date.now },
}, {strict: 'throw'});
module.exports = mongoose.model('tokens', tokenSchema);
Now if I start my node.js application, I can check MongoDBfor the indexes on this collection using db.getCollection('tokens').getIndexes(). This results in:
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "node-android.resettokens"
},
{
"v" : 1,
"key" : {
"created" : 1
},
"name" : "created_1",
"ns" : "node-android.resettokens",
"expireAfterSeconds" : 1800,
"background" : true,
"safe" : null
}
]
If I now shut down my node app, change the value of expires in the token schema to something different (an hour for example), restart my node app and check the collection indexes again, I end up having the same result. I noticed this behavior after setting the TTL feature to 10 seconds for the first time to test its workings, and later finding that changing the expires value still made my documents get deleted very quickly.
So my question is: is there a way to automatically overwrite the old expires index with a new one, or do I have to delete it myself? I the latter is the case, is there a way to do this in mongoose, or do I have to execute a db.getCollection('tokens').dropIndex('created_1') via the mongo shell myself?
I'm trying to save a document with mongoose according to the doc http://mongoosejs.com/docs/populate.html
First I call parent.save and inside the callback of parent.save I use child.save.
But when I check parent.childs I can see that no child has been added.
The parent schema is Home :
var HomeSchema = new Schema({
password : String,
draft : { type: Boolean, default: true },
edited : { type: Boolean, default: false },
guests : [{type : Schema.Types.ObjectId, ref : 'Guest'}],
_event : {type : Schema.Types.ObjectId, ref : 'Event'}
});
the child schema is Guest :
var GuestSchema = new Schema({
_home : {type : Schema.Types.ObjectId, ref : 'Home'},
firstname : String,
lastname : String,
coming : { type: String, default: 'dnk-coming' },
phone : String,
email : String,
address : String,
edited : { type: Boolean, default: false },
draft : { type: Boolean, default: true }
});
To avoid any misunderstanding, you have to know that this two Schema are included in my user schema :
var userSchema = mongoose.Schema({
homes:[homeSchema.HomeSchema],
events:[eventSchema.EventSchema],
guests:[eventSchema.guestSchema],
});
Now you should have all the required informations to completly understand the execution :
UserModel.findById(user._id, function(err, userFound) {
if (!err) {
/* cleaning draft*/
userFound.homes = that.clean(userFound.homes);
/* setting draft */
var HomeModel = mongoose.model("Home");
var homeModel = new HomeModel();
homeModel.draft = true;
if (userFound.homes === null) {
userFound.homes = [];
}
homeModel.save(function(err) {
if (!err) {
var GuestModel = mongoose.model("Guest");
var guestModel = new GuestModel();
guestModel._home = homeModel._id;
guestModel.save(function(err) {
if (!err) {
// #ma08 : According to the doc this line should'nt be required
//homeModel.guests.push(guestModel._id); so when I use this obviously the id is correctly set but when I try a populate after saving the populate do not work
userFound.homes.push(homeModel);
userFound.guests.push(guestModel);
userFound.save(function(err) {
if (!err) {
successCallback();
}
else {
errorCallback();
}
});
}
});
}
});
This treatement doesn't result in any error. But it doesn't work as intended when I stringify the user.guests I get :
guests:
[ { coming: 'dnk-coming',
edited: false,
draft: true,
_id: 53dcda201fc247c736d87a95,
_home: 53dce0f42d5c1a013da0ca71,
__v: 0 }]
wich is absolutly fine I get the _home id etc...
Then I stringify the user.homes and I get :
homes:
[ { draft: true,
edited: false,
guests: [],
_id: 53dce0f42d5c1a013da0ca71,
__v: 0 } ]
According to the doc guests should be setted, but it's not <-- this is my issue. Please help me to figure out what I'm doing wrong. I could set it manualy but according to the doc it's not suppose to work this way I think.
guestModel.save(function(err) {...
this is wrong because you are embedding the guests in the userSchema.
So skip the guestModel.save and just push the guestModel in userFound
An embedded document can never a reference. You can't point to it without obtaining the parent document. So you can't do both embedding and keeping a ref to the embedded document. You should choose between either embedding or adding a ref.
My suggestion would be to design your schemas like this. Store guests in a separate collection. Store the ref to guest in user and home schemas. If you want to store some relationship data you can store along with the ref like [{guestId:{type:Schema.Types.ObjectId,ref:'Guest'},field1:{type:...},field2:{...}..] and if you just want the ref [{type:Schema.Types.ObjectId,ref:'Guest'}]
all
I'm developing an application that store my multimedia catalog, I've JSON collection like this :
{ "_id" : ObjectId( "5142f55394474e2aac000001" ),
"contentType" : "binary/octet-stream",
"length" : 2732376,
"chunkSize" : 262144,
"uploadDate" : Date( 1363342677601 ),
"metadata" : {
"TIT2" : "Chase The Blues (Cameron McVey Remix)",
"TPE1" : "Terranova",
"TRCK" : "1/13",
"TALB" : "!K7",
"TPOS" : "1/1",
"TDRC" : "2000-06",
"TCON" : [
"Electronica",
"Trip-Hop" ],
"COMM" : [
"Chillout",
"Love",
"German",
"Berlin",
"2000s",
"Female Vocalists",
"Male Vocalists" ],
"TMED" : "CD",
"TMOO" : "Chill",
"TDOR" : "2000-06",
"TSO2" : "Various Artists",
"TPE2" : "Various Artists",
"TCMP" : "1",
"TSOP" : "Terranova",
"TIT1" : "Electronica",
"TPUB" : "SinedÃn Music",
"TLAN" : "eng",
"TYER" : [
"2000" ],
},
"md5" : "617401af615ac0c6cb1dee9a3f1b99e6",
"origin" : "Chase The Blues.109eb5ab5105a1caa505a26657f7f9a8.mp3",
"evolution" : null,
"insertDate" : Date( 1336662308000 ),
"tagSource" : "MusicBrainz",
"mediainfo" :
{ "Format" : "MPEG Audio",
"Format version" : "Version 1",
"Format profile" : "Layer 3",
"Duration" : "3mn 47s",
"Bit rate mode" : "Constant",
"Bit rate" : "96.0 Kbps",
"Channel(s)" : "1 channel",
"Sampling rate" : "44.1 KHz",
"Compression mode" : "Lossy",
"Stream size" : "2.60 MiB (100%)",
"Language" : "English"
}
}
so, as you can see, there are "metadata" and "mediainfo" array in the document
in the models.js , in the client side, I've rewrite the model parse function like this
var Audio_Model = Backbone.Model.extend({
idAttribute: "_id",
url: 'AudioModel',
urlRoot: 'AudioModel' ,
parse: function(response) {
// Check if response includes some nested collection data...
if (_.has(response, 'metadata')){
// Check if this model has a property called metadata
if (!_.has(this, 'metadata')) { // It does not...
// So instantiate a collection and pass in raw data
this.metadata = new Audio_Collection_Metadata(response.metadata);
} else {
// It does, so just reset the collection
this.metadata.reset(response.metadata);
}
delete response.metadata;
}
// Check if response includes some nested collection data...
if (_.has(response, 'mediainfo')){
// Check if this model has a property called mediainfo
if (!_.has(this, 'mediainfo')) { // It does not...
// So instantiate a collection and pass in raw data
this.mediainfo = new Audio_Collection_Mediainfo(response.mediainfo);
} else {
// It does, so just reset the collection
this.mediainfo.reset(response.mediainfo);
}
delete response.mediainfo;
}
return response;
}
});
so I've created two separate collection of 'metadata' and 'mediainfo'
the problem that I've is how to render 'metadata' and 'mediainfo' in html template because in 'mediainfo' and 'metadata' collection the key, values are not fixed and in 'metadata' some keys are array of values and the number of item in the array are not fixed
I've created backbone.marionette.itemview and compositeview for these two collections but I don't know how to render
Plase, someone have a solutions ?
Best Regards
finally I've fixed the problem myself with a data normalization, this is the new mongoose schema adopted :
var TagSchema = new mongoose.Schema({
value : {type : String, default: '', required: true}
});
var MetadataSchema = new mongoose.Schema({
name : {type: String, default: '', required : true},
values: [TagSchema]
});
var MediainfoSchema = new mongoose.Schema({
name : {type: String, default: ''},
value: {type: String, default: ''}
});
var StreamSchema = new mongoose.Schema({
_id: mongoose.Schema.ObjectId,
TIT2: {type : String, default: '', required: true},
metadata: [MetadataSchema],
mediainfo:[MediainfoSchema]
});
so that with sequence of CollectionView and CompositeView I can browse the entire model
Hope this can help someone