Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.
2 ώρες πριν, ajaxmonkey4hire είπε

Ναι. Αν θέλεις να το χρησιμοποιείς και από άλλα modules μπορείς να κάνεις το εξής:


'use strict'

const mongodb = require('mongodb');
const MongoClient = mongodb.MongoClient;
var   mongo;

class Mongo{
	constructor(server){
		this.server = server;
		this.client = null;
	}
	
	connect(cb, opts){
		opts = opts||{poolSize: 10, autoReconnect:true, useNewUrlParser: true};
		
		MongoClient.connect(this.server, opts, (e, dbClient)=>{ 
			this.client = e?null:dbClient;
			cb(e, this.client);
		});
	}	

	use(cb, dbName){
		if (cb){
			if (this.client&&this.client.isConnected()){
				cb(this.client.db(dbName));
			}else{
				this.connect((e, client)=>{
					cb(e?null:client.db(dbName));
				});
			}
		}
	}
}

module.exports.getMongoDb = function(server){
	mongo = mongo||new Mongo(server);
	return mongo;
}

κάνεις ένα require εκεί που θέλεις να το χρησιμοποιήσεις και καλείς το getMongoDb('το σερβερ σου') αν υπάρχει το mongo σου το επιστρέφει ειδάλλως καλεί το constructor, το φτιάχνει και μετά σου το επιστρέφει.

Αυτό είναι αρκετά κοντά σε αυτό που προσπαθώ να πετύχω, ωστόσο επειδή θα ήθελα να αποφύγω να χαλάσω τη δομή που ακολουθώ για όλα τα modules,
και πιο συγκεκριμένα να έχω μόνο μεταβλητές έξω από την κλάση που έχουν να κάνουν με τα imports (δηλ. ό,τι κάνω require), όπως τα δύο πρώτα constants που έχεις βάλει (αλλά όχι και την var mongo),
και να έχω μόνο ένα απλό module.exports = TheClass; που να κάνει export την ίδια την κλάση...

... θέλω να σε ρωτήσω αν υπάρχει τρόπος να γίνεται εσωτερικά στην κλάση με κάποια μέθοδο, κάποιον getter ίσως; Με static get ίσως;
 

Και αν δεν είναι εφικτό κάτι τέτοιο, τότε έτσι όπως έχεις το module.exports γίνεται να κάνει από default export την κλάση, και με διαφορετικό τρόπο (π.χ. getMongoDb) να κάνει export το function(server);

ώστε στο αρχικό module (bootstrap) που κάνω τη σύνδεση να μπορώ να κάνω τα εξής:

const Database = require("../core/database");
// ...
const db = new Database("...");
db.connect("...");

και σε όλα τα υπόλοιπα modules να κάνω το εξής:

const db = require("../core/database").getDb;
db.someMethod();

 

Δημοσ.
9 ώρες πριν, precursor είπε

@PC_MAGAS επειδή με μπερδεύουν όλα αυτά περί mongoDB ας το προσεγγίσουμε με τον δικό μου κώδικα (για να καταλάβω καλύτερα τι θα αλλάξω/προσθέσω). Συγνώμη για το πρήξιμο 😳

Για να συμπληρωθεί η όλη εικόνα, η κλάση Database όπως την περιγράψαμε:


"use strict";

const Sequelize = require("sequelize");

class Database {
  
  constructor(...) {
  }
  
  connect(DB_DIALECT, DB_USERNAME, DB_PASSWORD, DB_HOST, DB_PORT, DB_NAME) {
    
        this.sequelize = new Sequelize(DB_DIALECT + "://" 
             + DB_USERNAME + ":" + DB_PASSWORD + "@" + DB_HOST + ":" + DB_PORT + "/" + DB_NAME, {
            operatorsAliases: false,
            logging: false,
            define: {
                charset: 'utf8'
            }
        });

        // Successful connection or not?
        this.sequelize.authenticate().then(() => {
            console.log("Successfully connected to the database.");
        }).catch((err) => {
            console.log("Unable to connect to the database: " + err);
        });
  }

  // CRUD

}

module.exports = Database;

Οπότε που πρέπει να "κουμπώσω" και τι για να είναι προσβάσιμο από όλα τα controllers (και συνεπώς και από models) το Database object που έκανε το connection 🤔

Όπως το περιγράφεις στο Bootstrap κούμπωσε τo new Database() και μετά πέρνα το instance σαν Depedency στον constructor κάθε Object. Μετά εντός του class Database τοποθέτησε μια μέθοδο Use που θα παίρνει σαν όρισμα μια callback και μέσω callback θα λαμβάνει το error στο πρώτο όρισμα αυτής και σαν δεύτερο όρισμα το this.sequelize .

  • Like 1
Δημοσ.
10 ώρες πριν, precursor είπε

Αυτό είναι αρκετά κοντά σε αυτό που προσπαθώ να πετύχω, ωστόσο επειδή θα ήθελα να αποφύγω να χαλάσω τη δομή που ακολουθώ για όλα τα modules,
και πιο συγκεκριμένα να έχω μόνο μεταβλητές έξω από την κλάση που έχουν να κάνουν με τα imports (δηλ. ό,τι κάνω require), όπως τα δύο πρώτα constants που έχεις βάλει (αλλά όχι και την var mongo),
και να έχω μόνο ένα απλό module.exports = TheClass; που να κάνει export την ίδια την κλάση...

... θέλω να σε ρωτήσω αν υπάρχει τρόπος να γίνεται εσωτερικά στην κλάση με κάποια μέθοδο, κάποιον getter ίσως; Με static get ίσως;
 

Και αν δεν είναι εφικτό κάτι τέτοιο, τότε έτσι όπως έχεις το module.exports γίνεται να κάνει από default export την κλάση, και με διαφορετικό τρόπο (π.χ. getMongoDb) να κάνει export το function(server);

ώστε στο αρχικό module (bootstrap) που κάνω τη σύνδεση να μπορώ να κάνω τα εξής:


const Database = require("../core/database");
// ...
const db = new Database("...");
db.connect("...");

και σε όλα τα υπόλοιπα modules να κάνω το εξής:


const db = require("../core/database").getDb;
db.someMethod();

Την var mongo έξω από την class δεν μπορείς να την αποφύγεις αν θέλεις να χρησιμοποιησης την ίδια instance από διαφορετικά modules. Μπορείς να έχεις πολλαπλα exports άλλα όχι και default με αυτά. 

 

 

 

  • Like 1
Δημοσ.
Στις 20/4/2019 στις 5:21 ΠΜ, precursor είπε

Καλησπέρα :)

Θα ήθελα τη βοήθειά σας επειδή όσο και αν ψάχνω στο Google δεν έχω καταφέρει κάτι.

Φτιάχνω ένα web app σε Node.js και χρησιμοποιώ το Sequelize ORM για να συνδεθώ στη βάση δεδομένων (PostgreSQL, αν και δεν έχει ιδιαίτερη σημασία αυτό). Το φτιάχνω με αρχιτεκτονική MVC και επειδή είμαι συνηθισμένος στις κλάσεις (από Java και C#) και μπερδεύομαι εύκολα με κώδικα χωρίς κλάσεις, θέλω τα πάντα να είναι αυστηρά μέσα σε κλάσεις! Δηλαδή κάθε module (δηλ. αρχείο .js) να έχει πάνω-πάνω τα requires του μετά να ακολουθεί όλος ο κώδικας μέσα σε class Example {...} και τέλος ένα module.exports = Example;

Το πρόβλημα είναι ότι δεν μπορώ σχεδόν ποτέ να βρω ολοκληρωμένα παραδείγματα με κλάσεις - πάντα κάτι θα λείπει ή θα υπάρχει σπαγγέτι κώδικας και μπερδεύομαι και δεν μπορώ να ενώσω τα κομμάτια...

Αν κάποιος γνωρίζει λοιπόν, θα ήθελα οδηγίες για να πετύχω το εξής:
 


"use strict";

const Sequelize = require("sequelize");

class Database {
  
  constructor() {
  }
  
  ...

}
    
module.exports = Database;

 

1)

Πού και πώς πρέπει να βάλω το db = new Sequelize(...); ώστε να έχω μόνο ένα instance και δηλ. μόνο μία σύνδεση με τη βάση δεδομένων και να μην καταλήγω να κάνω new σύνδεση σε κάθε request;;;

2)

Και πέρα από την κλάση Database, στις υπόλοιπες κλάσεις πώς καλώ και παίρνω το db (διατηρώντας φυσικά μία σύνδεση);;; Υπόψη ότι όλες οι υπόλοιπες κλάσεις θα έχουν την ίδια μορφή. Σκεφτόμουν αρχικά μήπως έβαζα το new Sequelize μέσα σε μια μέθοδο static get db() αλλά μετά κατάλαβα ότι έτσι θα κάνω νέα σύνδεση κάθε φορά που καλώ την Database.db

3)

Τέλος, όσον αφορά τις ρυθμίσεις options που βάζω μέσα στο new Sequelize, με λίγα λόγια τι κάνουν τα min, max και acquire του pool π.χ. αν περιμένω να έχω 1000 users online τι πρέπει να προσέξω για να έχω αρκετά διαθέσιμα connections; 

Αναρωτιέμαι για ποιον λόγο φτιάχνεις την wrapper class. Προσωπικά την χρησιμοποιώ στην mongo για δυο λόγους:

1. Αποφεύγω τα πολλαπλα  connect που κοστίζουν χρόνο 

2. Κάνω query result caching μέσα στην wrapper class

Και τα δυο κάνουν την εφαρμογή πιο γρήγορη και ικανοποιούν the need for speed. Το "στύλε" είναι, για έμενα, δευτερεύουσας σημασίας. Προτιμώ πάντα αυτό που δινει την καλύτερη performance και ας μην είναι πάντα το "ομορφότερο"

 

Δημοσ.
1 ώρα πριν, ajaxmonkey4hire είπε

Την var mongo έξω από την class δεν μπορείς να την αποφύγεις αν θέλεις να χρησιμοποιησης την ίδια instance από διαφορετικά modules. Μπορείς να έχεις πολλαπλα exports άλλα όχι και default με αυτά. 

Μπορώ τουλάχιστον με πολλαπλά exports - με δύο συγκεκριμένα - με το ένα να παίρνω την κλάση και με το άλλο το function που επιστρέφει το instance; Δηλαδή να μπορώ να κάνω require("../core/database").getClass και require("../core/database").getDb ;

3 λεπτά πριν, ajaxmonkey4hire είπε

Αναρωτιέμαι για ποιον λόγο φτιάχνεις την wrapper class.

Χάνομαι εύκολα στον κώδικα και πονοκεφαλιάζω (ειδικά όταν επιστρέφω σε κάτι που έφτιαξα μετά από καιρό) αν δεν τον βλέπω με κλάσεις... ¯\_(ツ)_/¯

7 ώρες πριν, PC_MAGAS είπε

Μετά εντός του class Database τοποθέτησε μια μέθοδο Use που θα παίρνει σαν όρισμα μια callback και μέσω callback θα λαμβάνει το error στο πρώτο όρισμα αυτής και σαν δεύτερο όρισμα το this.sequelize .

Δηλαδή κάπως έτσι;

// Το use που είχες βάλει με τις αλλαγές που μου είπες (αν το έκανα σωστά)
use(cb) {
  if(!this.sequelize){
    return cb(err);
  }
  cb(null,this.sequelize);
}

// Ένα ακόμα use του ajaxmonkey4hire
use(cb, dbName){
  if (cb){
    if (this.client && this.client.isConnected()){
      cb(this.client.db(dbName));
    }
    else {
      this.connect((e, client)=>{
        cb(e?null:client.db(dbName));
      });
    }
  }
}

Με τη μέθοδο use, απ' ό,τι καταλαβαίνω, μπορώ να βλέπω αν υπάρχει σύνδεση στη βάση, αν δεν υπάρχει να λαμβάνω error και αν υπάρχει να λαμβάνω το this.sequelize handler σωστά; Και αν θέλω κάνω και επανασύνδεση αντί να βγάλω ένα σκέτο error. Σωστά όλα αυτά;

Θα σου πω ψέματα όμως αν πω ότι κατάλαβα πώς θα είναι αυτό το callback που θα πρέπει να περάσω αν και έχω μια μικρή ιδέα: https://stackoverflow.com/questions/31780872/what-is-cb-in-node

Δεν μπορώ αντί για την use να βάλω κάποιον getter;

set sequelize(object) {
  this._sequelize = object;
}

get sequelize() {
  // if no error
  return this._sequelize;
  // else errors, reconnect etc.
}

 

7 ώρες πριν, PC_MAGAS είπε

Όπως το περιγράφεις στο Bootstrap κούμπωσε τo new Database() και μετά πέρνα το instance σαν Depedency στον constructor κάθε Object.

Οκ. Κάτι ακόμα πάνω σε αυτό. Ο Express μου δίνει τη δυνατότητα να περνάω μεταβλητές στο response object με το res.locals. Μιας και στον constructor του κάθε controller περνάω τα res, req και next και μιας και θα ήθελα να αποφύγω να περάσω και το instance ή περισσότερα arguments...

... θα ήταν καλή ιδέα να βάλω το instance στο res.locals ή όχι; Δηλαδή:
 

res.locals.db = db;

Bootstrap.loadController(req, res, next);

 

Σας ευχαριστώ πολύ για τη βοήθεια ^_^

Δημοσ.
50 λεπτά πριν, precursor είπε

Δεν μπορώ αντί για την use να βάλω κάποιον getter;

Well  υποθέσαμε ότι το connection είναι ασύγχρονο έτσι δεν θα μπορείς να παίζεις εύκολα μπάλα με getter και setter. Βάση του Documentation http://docs.sequelizejs.com/manual/usage.html getter και setter μπορείς να παίξεις λόγο ότι η function για  τα queries είναι promices. Από την άλλη έχω απορία η προσεγγίσεις μας πως θα γίνουν ευκόλως unit testable.

Ακόμη εύκολα γλιτώνεις το callback hell κάπως έτσι πχ. έστω ο κώδικας:

const someObjWithCallbackFunc= new SomeObj();
someObjWithCallbackFunc.functionWithCallbackAsParameter((err,params)=>{
 //Doing stuff
});

Στον κώδικα:

const maFunction=(err,params)=>{
 //Doing stuff
};

const someObjWithCallbackFunc= new SomeObj();
someObjWithCallbackFunc.functionWithCallbackAsParameter(maFunction);

Δηλαδή κάνε τις functions σου από ανώνυμες, well όσο ποιο επώνυμες είναι δυνατόν. Ακόμα φρόντισε οι function/μέθοδοι να είναι όσο ποιο "αυτόνομες" δυνατόν περνώντας σαν παράμετρο ότι χρειάζεται. Δηλαδή να σκέφτεσαι κάθε λογικό module σαν ένα αυτόνομο κομμάτι που ότι τρίτο παίρνει θα το παίρνει μέσω παραμέτρων, έτσι θα γίνετε πιο εύκολο προς αυτοματοποιημένο test (unit test).

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...