Node require - i don't understand this code - node.js

I'm starting to learn node.js and mongoose and I do not understand the following code.
I have 2 files: app.js and idea.js
app.js
const mongoose = require('mongoose')
require('./models/Idea')
const Idea = mongoose.model('ideas')
idea.js
const mongoose1 = require('mongoose')
const Schema = mongoose1.Schema
const IdeaSchema = new Schema(
{
title: { type:String, required:true},
details: {type:String, required:true},
date: {type:Date, default:Date.now()}
}
)
mongoose1.model('ideas', IdeaSchema)
When I run app.js, no error occurs. How is it possible? I did not export anything from the idea.js file!
How did the app.js file get access to the ideas model?

require is cached. So, this:
let obj1 = require('an_object');
let obj2 = require('an_object');
will load the object in the first line, and return that same object from cache in the second line. This holds even if the two requires are in different files. Since obj1 and obj2 are references to the same object, if obj1 gets modified, obj2 also gets modified (because they're one and the same).
You did not export anything from Idea, but it doesn't matter; the purpose of Idea was to modify the mongoose object, not to return anything.
Simplified:
// storage.js
exports.hello = 'Mumble mumble';
// mod_storage.js
let modding_storage = require('./storage');
modding_storage.hello = "Hello, world!";
// main.js
let main_storage = require('./storage');
require('./mod_storage');
console.log(main_storage.hello);
// => Hello, world!
mod_storage changed modding_storage, but modding_storage is the same object as main_storage; change one, both change.

Related

can not get cascade DDS value for SharedObjectSequence

I have a test like this, but i can not get the 'sharedMap' in 'sharedSeq1' value, i don't know how to get the 'remoteFluidObjectHandle' value.
import {MockContainerRuntimeFactory, MockFluidDataStoreRuntime, MockStorage} from "#fluidframework/test-runtime-utils";
import {SharedObjectSequence, SharedObjectSequenceFactory} from "#fluidframework/sequence";
import * as mocks from "#fluidframework/test-runtime-utils";
import {SharedMap} from "#fluidframework/map";
import {IFluidHandle} from "#fluidframework/core-interfaces";
const mockRuntime: mocks.MockFluidDataStoreRuntime = new mocks.MockFluidDataStoreRuntime();
describe('ShredObjectSequence', function () {
it('should get synchronization data from another shared object', async function () {
const dataStoreRuntime1 = new MockFluidDataStoreRuntime();
const sharedSeq1: SharedObjectSequence<IFluidHandle<SharedMap>> = new SharedObjectSequence(mockRuntime, 'shareObjectSeq1', SharedObjectSequenceFactory.Attributes,)
const containerRuntimeFactory = new MockContainerRuntimeFactory();
dataStoreRuntime1.local = false;
const containerRuntime1 = containerRuntimeFactory.createContainerRuntime(
dataStoreRuntime1,
);
const services1 = {
deltaConnection: containerRuntime1.createDeltaConnection(),
objectStorage: new MockStorage(),
};
sharedSeq1.initializeLocal();
sharedSeq1.connect(services1);
const dataStoreRuntime2 = new MockFluidDataStoreRuntime();
const containerRuntime2 = containerRuntimeFactory.createContainerRuntime(
dataStoreRuntime2,
);
const services2 = {
deltaConnection: containerRuntime2.createDeltaConnection(),
objectStorage: new MockStorage(),
};
const sharedSeq2: SharedObjectSequence<IFluidHandle<SharedMap>> = new SharedObjectSequence(mockRuntime, 'shareObjectSeq2', SharedObjectSequenceFactory.Attributes,)
sharedSeq2.initializeLocal();
sharedSeq2.connect(services2);
// insert a node into sharedSeq2, it will sync to sharedSeq1
sharedSeq2.insert(0, [<IFluidHandle<SharedMap>>new SharedMap('sharedMapId', mockRuntime, SharedMap.getFactory().attributes).handle])
containerRuntimeFactory.processAllMessages();
// next case is passed, it show we got the sharedSeq2 changed
expect(sharedSeq1.getLength()).toBe(1)
const remoteFluidObjectHandle = await sharedSeq1.getRange(0, 1)[0];
// at here, i get error: Cannot read property 'mimeType' of null, it cause by remoteFluidObjectHandle.ts:51:30
const sharedMap = await remoteFluidObjectHandle.get()
expect(sharedMap).not.toBeUndefined()
});
});
run this test will get 'Cannot read property 'mimeType' of null' error, it caused by 'remoteFluidObjectHandle.ts:51:30'
The fluid mocks have very limited and specific behaviors, it looks like you are hitting the limits of them. You'll have better luck with an end-to-end test, see packages\test\end-to-end-tests. These use the same in-memory server as our as the playground on fluidframework dot com. The in-memory server uses the same code as tinylicious, our single process server and routerlicious, our docker based reference implementation.

Node js put schemas in other folder

i have created basic node project in which i created model folder inside model folder i have schema folder and index.js
in schema folder have all schema of my project and in index.js i write some thing like this
var s1 = require('./schema/schema1');
var s2 = require('./schema/schema2');
module.export = function(app) {
schema1= s1 ;
schema2= s2 ;
}
and in controller file i m accessing model like this
var model = require('./models/');
model.schema1.find(function(err, data) {
})
but this above code not working its give me error TypeError: Cannot read property 'find' of undefined but when i try something like this in controller
var schema1= require('../models/schema/schema1');
schema1.find(function(err,data){});
its working fine but i want 1st structure in my project i using mongoose, express, node, mongodb.
Please help i don't know what i m doing wrong
Your index.js exports a function returning nothing. Either do:
var s1 = require('./schema/schema1');
var s2 = require('./schema/schema2');
module.exports = function (app) {
return {
schema1: s1,
schema2: s2
}
}
Then require like this: var model = require('./models/')(); (notice the (), it's a function, you must call it to get the returned object).
Or, if you don't use the app parameter at all:
var s1 = require('./schema/schema1');
var s2 = require('./schema/schema2');
module.exports = {
schema1: s1,
schema2: s2
}
Then you can simply var model = require('./models/'); (no () here)).
You also had a typo on module.exports, you forgot the s.
pass your Schema to second file do something like this in first file :
var mySchema = new Schema({
// my props
});
require('./app/anotherFolder.js')(mySchema)

Mongoose validation error when using custom validator

Following is the Schema which is not working correctly with custom validator-
var mongoose = require('mongoose');
var userSchema = new mongoose.Schema({
email : { type: String, validate: lengthValidator },
});
// Length validator for email
var lengthValidator = function(val){
if(val && val.length >= 6 )
return true;
return false;
};
var User = mongoose.model('User',userSchema);
module.exports = User;
Error -
Error: Invalid validator. Received (undefined) undefined. See http://mongoosejs.com/docs/api.html#schematype_SchemaType-validate
at SchemaString.SchemaType.validate (/MY_PROJECT_PATH/node_modules/mongoose/lib/schematype.js:416:13)
at SchemaString.SchemaType (/MY_PROJECT_PATH/node_modules/mongoose/lib/schematype.js:38:13)
at new SchemaString (/MY_PROJECT_PATH/node_modules/mongoose/lib/schema/string.js:24:14)
at Function.Schema.interpretAsType (/MY_PROJECT_PATH/node_modules/mongoose/lib/schema.js:367:10)
at Schema.path (/MY_PROJECT_PATH/node_modules/mongoose/lib/schema.js:305:29)
at Schema.add (/MY_PROJECT_PATH/node_modules/mongoose/lib/schema.js:217:12)
at new Schema (/MY_PROJECT_PATH/node_modules/mongoose/lib/schema.js:73:10)
at Object.<anonymous> (/MY_PROJECT_PATH/models/users.js:2:18)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
However if I remove validate then it is working correctly as I checked by changing the type from String to Number.
Let me know what i am doing wrong?
The issue you're experiencing is related to hoisting. The way that you've written your validation function means that at the time you're passing it into the schema it's an undefined value; it's not until afterwards that the variable gets set.
Here's a really basic example of the problem.
var thing = {
foo: bar
}
var bar = function () {
alert('hello!');
}
thing.foo();
When thing.foo() is called, it will throw an error. Why? Because this is how JavaScript interprets what I wrote:
var bar;
var thing = {
foo: bar // At this point, bar is undefined
}
bar = function () {
alert('hello!');
}
thing.foo();
The same thing is happening to your code. When you set the validate property in the schema to lengthValidate, it hasn't been defined yet.
There's two ways to fix it.
Move the validation function definition above the schema definition in the code.
Use function lengthValidator(val) instead of var lengthValidator = function(val)

Why doesn't my Mongoose schema method "see" my required object?

I'm really confused about a variable scope issue with a file required via a path in a config file. Why does my Mongoose schema method "see" the required objects when called from within the model file but not when called from my app.js file? I'm convinced that I must be doing something obviously wrong but I can't see it.
The Node project has the following (simplified) structure:
|models
-index.js
-story.js
-post.js
-app.js
-config.js
This is config.js:
config = {};
config.test = 'test';
config.models = __dirname + '/models';
module.exports = config;
This is story.js:
var config = require('../config.js');
var models = require(config.models);
var foo = {};
foo.bar = 'baz';
var storySchema = mongoose.Schema
({
author: {type: mongoose.Schema.Types.ObjectId},
root: {type: mongoose.Schema.Types.ObjectId, default: null}
});
storySchema.methods.test = function()
{
console.log(foo.bar);
console.log(config.test);
console.log(models);
}
var Story = exports.model = mongoose.model('story', storySchema);
When I create a new Story in app.js and call its test() method, I get this output:
baz (so I know it's seeing objects in the same file)
test (so I know it's seeing variables in the config file)
{} (this "should" log my models object but it logs an empty object, why?)
When I create a new Story object within the story.js file, and run it (node ./models.story.js) the values returned are as expected (the models object is logged rather than an empty object).
Update, here are the index.js and app.js files:
index.js:
module.exports = {
post: require('./post'),
story: require('./story')
};
app.js:
var config = require('./config');
var models = require(config.models);
var story = new models.story.model();
story.test();
I believe the issue is that you've created a circular dependency. Story executes require(config.models) which requires Story again inside index.js.
Rather than storing a string and requireing it everywhere, try storing the models directly in config.models:
config.js
module.exports = {
test: 'test',
models: require(__dirname + '/models')
};
In case anyone runs into this same issue, I wanted to point to a couple resources I came across that helped me resolve the issue. As ssafejava pointed out, the problem does have to do with circular dependency (although ssafejava's solution did not entirely resolve the issue) . What worked for me was designing this dependency out of my application but there are other options if doing so is not possible. See the following issues' comments for a better explanation (in particular, see 'isaacs' comments):
https://github.com/joyent/node/issues/1490
https://github.com/joyent/node/issues/1418

Understanding exports in NodeJS

I don't think I quite understand how exports work in Node.js. In a bit of sample code, I noticed the exports object used in this manner:
exports = mongoose = require('mongoose')
mongoose.connect(config.db.uri)
exports = Schema = mongoose.Schema
What is happening behind the scenes when you use exports = twice like that? Looks to me like "mongoose" should not be exported. I did this quick test:
var foo
, bar
exports = foo = 'foo'
exports = bar = 'bar'
// reports 'bar' only
console.log(exports)
and the second test does overwrite the first export.
My guess is the original author of that sample code is confused about module.exports vs exports. To use the exports object, you must add properties to it like this:
exports.size = 42;
If you re-assign the exports variable to a new object, you basically lose access to the global exports object that node.js provided for you. If you do this twice or three or N times, the effect is the same. It's useless. For example: mod_b.js
var realExports = exports;
realExports.height = 42;
var exports = {};
exports.weight = 43;
And in mod_a.js
var mod_b = require('./mod_b');
console.dir(mod_b);
Run node mod_a.js and you get:
{ height: 42 }
Notice height is there but weight is not. Now, what you can do is assign module.exports to be an object, and that is the object that will be returned when another module requires your module. So you will see things like.
var x = 10;
var y = 20;
module.exports = {x: x, y: y};
Which will do what you expect. Here's some informative articles on the details.
Node.js Module – exports vs module.exports
What is the purpose of NodeJS module.exports and how do you use it?
Mastering Node
As an extension to #Peter-Lyons answer, your example is valid, your test case is incorrect.
Exporting variables like this is not recommended, but by doing that, you are exposing this variables into a global namespace.
e.g. test0.js
'use strict';
var assert = require('assert');
var test1 = require('./test1');
assert(globalVar1 === 123);
assert(globalVar2.a === 123);
test1.js -- mind the missing 'use strict';
exports = globalVar1 = 123;
exports = globalVar2 = {a:123};
Once again, it's valid, but not recommended.
Cheers.

Resources