-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnotesMongoDB.js
1550 lines (1127 loc) · 51.4 KB
/
notesMongoDB.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
***************************************************************************************************
********************************** MONGOD **********************************************
***************************************************************************************************
***************************************************************************************************
connection sans mongoose :
1- partir mongod.
pas besoin de creer la db avant et sans schema ca n apparait pas dnas compass=> ca viendra.
const MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/TodoApp', (err, db) => {
if(err){
return console.log('y a une erreur'); //va bloquer l execution avec le return
}
console.log('Connecté a mongoDB');
db.close();
});
pour la voir apparaitre dans compass, il faut ajouter du data :
AVEC DB.COLLECTION('NOMDELACOLLECTION').INSERTONE(ARG1: LE DATA EN OBJ, ARG2 UN CB POUR ERR, ET VOIR LE RESULTAT. );
MongoClient.connect('mongodb://localhost:27017/TodoApp', (err, db) => {
if(err){
return console.log('y a une erreur'); //va bloquer l execution avec le return
}
console.log('Connecté a mongoDB');
//Ajouter une collection - du data
db.collection('Todos').insertOne({
test: 'un truc intelligent',
completed: false
}, (err, result) => {
if(err){
return console.log('y a une erreur', err); //va bloquer l execution avec le return
}
console.log(JSON.stringify(result.ops));
});
db.close();
});
donne :
Connecté a mongoDB
[{"test":"un truc intelligent","completed":false,"_id":"598c9c91850703795697458d"}]
Connecté a mongoDB
[{"name":"AXE-Z","age":2,"location":{"lat":45,"lng":-73},"_id":"598ca9acc79d8579be8766a3"}]
RESULT.OPS[0] :
MongoClient.connect('mongodb://localhost:27017/TodoApp', (err, db) => {
if(err){
return console.log('y a une erreur'); //va bloquer l execution avec le return
}
console.log('Connecté a mongoDB');
db.collection('Users').insertOne({
name: 'AXE-Z',
age: 2,
location: 'Mtl'
}, (err, result) => {
if(err){
return console.log('y a une erreur', err); //va bloquer l execution avec le return
}
console.log(JSON.stringify(result.ops, undefined, 2)); //ca donne un meilleur preview .
console.log(result.ops[0]._id.getTimestamp()) //2017-08-10T23:56:44.000Z
});
db.close();
});
/*
[
{
"name": "AXE-Z",
"age": 2,
"location": "Mtl",
"_id": "598cf2bcd67f5d7afcb8fe0b"
}
]
*/
ObjectID()
si on veut le gerer soit meme , mais mongo le fait tout seul, donc fuck it
//const MongoClient = require('mongodb').MongoClient;
const { MongoClient, ObjectID } = require('mongodb'); //meme chose qu en haut.
let obj = new ObjectID();
console.log(obj)//598dc61663c1807e419795d7 //PAREIL
console.log(obj)//598dc61663c1807e419795d7 //PAREIL
console.log(new ObjectID()) //598dc65a04c83f7e5a6e98a5 DIF
console.log(new ObjectID()) //598dc65a04c83f7e5a6e98a6 DIF
///////////////////////FIND////////////////////////////////////////TOARRAY() native
db.collection('Todos').find().
TOARRAY() methode qui retourne une promise
MongoClient.connect('mongodb://localhost:27017/TodoApp', (err, db) => {
if(err){
return console.log('y a une erreur'); //va bloquer l execution avec le return
}
console.log('Connecté a mongoDB');
//TOUT
db.collection('Todos').find().toArray() //va nous retourner un promise avec TOUT
.then(data => {
console.log(data) //js normal
console.log(JSON.stringify(data, undefined,2)); // du json
})
.catch(err => {
console.log(err)
});
//db.close();
});
CRITERES
//avec critere de false a completed // retourne que ce qui est false
db.collection('Todos').find({completed: false}).toArray() //va nous retourner un promise avec compelted false
.then(data => {
....
//AVEC CRITERE _id // faut passer par new ObjectID
db.collection('Todos').find({
_id: new ObjectID('598c9c91850703795697458d')}).toArray() //va nous retourner un promise avec _id
.then(data => {
//
//////////////////find//////////////////////////////////////count native
db.collection('Todos').find().count() //va nous retourner un promise avec TOUT
.then(data => {
console.log(data) //js normal
console.log(JSON.stringify(data, undefined,2)); // du json
})
.catch(err => {
console.log(err)
});
2 et 2 va compter les
//////////////////delete//////////////////////////////////////native
const { MongoClient, ObjectID } = require('mongodb'); //meme chose qu en haut.
MongoClient.connect('mongodb://localhost:27017/TodoApp', (err, db) => {
if(err){
return console.log('y a une erreur'); //va bloquer l execution avec le return
}
console.log('Connecté a mongoDB');
//deletemany delete tout ce qui est dans le query
db.collection('Todos').deleteMany({text: 'cour'});
.then(result => {
console.log(result)
});
//deleteOne delete le premier trouve qui est dans le query
db.collection('Todos').deleteOne({text: 'cour'});
.then(result => {
console.log(result)
});
//findOneAndDelete fait le boulot et retourne l object detruit.
db.collection('Todos').findOneAndDelete({completed: false})
.then(result => {
console.log(result) //{ lastErrorObject: { n: 0 }, value: null, ok: 1 }
});
retour:
// { lastErrorObject: { n: 1 },
// value:
// { _id: 598f25003d88bf0864a87f66,
// text: 'caca2',
// completed: false },
// ok: 1 }
//db.close();
});
//////////////////UPDATE//////////////////////////////////////native
update est plus demandant cote code
findOneAndUpdate (filter(obj), update(obj), options(obj), callback)
update === updateOperator $set , $inc , $rename $unset
MongoClient.connect('mongodb://localhost:27017/TodoApp', (err, db) => {
if(err){
return console.log('y a une erreur'); //va bloquer l execution avec le return
}
console.log('Connecté a mongoDB');
//update est plus demandant cote code
//598dd092fe01ae7db30f3f53
///findOneAndUpdate (filter(obj), update(obj), options(obj), callback)
// update === updateOperator $set , $inc , $rename $unset
db.collection('Todos').findOneAndUpdate(
/*filter*/ {_id: new ObjectID('598dd092fe01ae7db30f3f53')},
/*update*/ { $set : {completed: false} }, //dans un obj, dire la sorte d update, et mettre ce qu on veut .
/*option*/ {returnOriginal: false }, //par defaut ce qui est retourné est la fiche AVANT la modif, false = new
/*callback*/
)
.then(result => {
console.log(result)
})
.catch(err => {
console.log(err)
});
});
//retour ===
/*{ lastErrorObject: { updatedExisting: true, n: 1 },
value:
{ _id: 598dd092fe01ae7db30f3f53,
text: 'walk le chien',
completed: false },
ok: 1 }*/
***************************************************************************************************
********************************** MONGOD **********************************************
***************************************************************************************************
***************************************************************************************************
notes extra d un autre cour the complete dev, guide to mongoDB :
////IMPORTEZ MONGOOSE. CONNECTION PACKAGE QUI CONNECTE AVEC MONGODB////////////////////////////////////////////
//test_helper.js
//import moogoose et initialize.
const mongoose = require('mongoose');
mongoose.Promise = global.Promise; //ES6 faut dire quel type de promise.
//DONE FUNCTION
DONE = C EST POUR LE TESTING, PUISQUE LES TEST SONT ASYNC , IL FAUT DIRE A MOCHA D ATTENDRE, QUE LA REPONSE
VA P-E PRENDRE DU TEMPS. DONC AVEC DONE, ON LUI DIT DE RESTER, ET DONE() LUI DIT DE CONTINUER.
//DEPRECATION, CA FONCTIONNE ,MAIS FAUT CHANGER CA !!!
//va voir localement // pas besoin que users_test soit la d avance, mongoosse et mogodb vont la creer si pas la.
//pour s assurer que mongo connecte avant mocha: BEFORE.
before(done => {
mongoose.connect("mongodb://localhost/users_test");
mongoose.connection
.once("open", () => {
done();
}) //once, ne fait qu une fois.
.on("error", error => {
console.warn("Avertissement", error);
});
});
//open et error sont des event que mongoose reconnait. Et peu importe le temps de connection, ils seront ok.
//DEPRECATION, CA FONCTIONNE ,MAIS FAUT CHANGER CA !!! fonctionne bien avec mongose@4.6.6
////Importez mongoose. package de CONNECTION avec mongoDB////////////////////////////////////////////
///pour ne pas poluer la db
//done est un truc qui check si c est fait avant d ajouter le user joe. BEFOREEACH
beforeEach((done) => {
//efface tous les users, prend un CB , pour dire que c est fini
mongoose.connection.collections.users.drop(() => {
//pret pour la suite
done();
});
});
////LA SCHEMA////////////////////////////////////////////////////////////////////////////////////////////
///user.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserSchema = new Schema({ ///forme de la schema
name: String
});
const User = mongoose.model('user', UserSchema) //le model pour mongo.
module.exports = User; //exporte que le model.
////LA SCHEMA////////////////////////////////////////////////////////////////////////////////////////////
diference entre User et new User. User ici est le nom du model, de la database .
quand on veut traiter , comme en lecture ( find , findOne ) avec TOUT la Db , c est User
Quand on veut ajouter un truc, comme une ficher, (joe = new User({name: 'Joe'})), on creer une instance
////Tester la DB avec MOCHA/////////////CREER UN USER///////////////////////////////////////////////////
//TEST MOCHA - polue la DB ..
const assert = require('assert');
const User = require('../src/user'); //notre model User. notre DB
//sans assert, u ntest est quasi inutile, assert lui verifie vraiment si une condition est remplie.
describe('Creer une fiche user', () => {
it('Sauvegarde un user', (done) => {
//assert(1+1 === 2); //Assertion ici, de deviner ce qui devrait arriver.
const joe = new User({
name: 'Joe'
}); //creer de l instance, creer ce qui va dans le db
joe.save() //save est une des function d un model mongoose qui retourne un promise
.then(() => {
//ca fonction ? isNew, est une option de mongoose. si false ca veut dire que c est dans la DB
assert(!joe.isNew); //regarde si false. true veut dire que c est dans mocha, mais pas dans mongo.
done();
});
});
});
//npm run test; ... passing 1 + 1 === 2 , malade !!
// "scripts": {
// "test": "mocha" ///juste mocha, il va trouver le rep test et passer tous les it function.
// },
////Tester la DB avec MOCHA/////////////CREER UN USER///////////////////////////////////////////////////
////Tester la DB avec MOCHA/////////////CHERCHER SUR LA DB///////////////////////////////////////////////////
// _id:5960de91b36b1f1f056369a3 //OU TROUVER AVEC LE OBJECT_ID
// name:"Joe" //TROUVER AVEC LE NOM
// __v:0
//mongoose function
// notreModel.find() //trouve TOUS LES match
// notreModel.findOne() //trouve LE PREMIER match
//TEST MOCHA -
const assert = require('assert');
const User = require('../src/user'); //notre model User. notre DB
//LIRE LA DB.
describe("LIRE une fiche user", () => {
//le but est de faire une fiche pour la tester, pour etre sur qu on a du data a lire.
let joe; //pour avoir acces en bas.
beforeEach((done) => {
joe = new User({name: 'Joe'});
joe.save() //save retourne un promisse ..
.then(() => done());
})
it("trouver Joe", (done) => {
User.find({name:'Joe'}) //comme save, retourne une promise
.then((users) => {
//console.log(users); [ { _id: 5960f2a236497821e7605730, name: 'Joe', __v: 0 } ]
assert(users[0]._id.toString() === joe._id.toString()) //Joe aura son id de mongoose, avant que mongo le save.
done();
});
});
it("trouver un ID particulier", (done) => {
User.findOne({ _id : joe.id}) //mongo est capable dedealer avec ca. return promisse
.then((user ) => {
assert(user.name === 'Joe')
done();
});
});
});
//METTRE.TOSTRING() POUR ANALYSER LE _ID.
//FAIT INTERESSANT, C EST MONGOOSE QUI DONNE LE _ID , ET IL SERA LE MEME UNE FOIS DANS MONGO.
//DONC AVANT MEME QUE LE SAVE SOIT FINI DNAS MONGO , ON PEUT TESTER LE _ID
ASSERT(USERS[0]._ID === JOE._ID) USERS[0]._ID == DANS MONGODB || JOE._ID == MONGOOSE QUI L ATTRIBUT.
//LES DEUX ON LE MEME ID, PARCONTRE !!! MONGOOSE ET MONGO WRAP _ID DE MANIERE DIFFERENTE.
//_ID:OBJECTID // MAIS AVEC .TOSTRING() CA SE BALANCE. assert(users[0]._id.toString() === joe._id.toString())
//RESULTAT dans le terminal
// LIRE une fiche user
[ { _id: 5960f2a236497821e7605730, name: 'Joe', __v: 0 } ]
notreModel.find() //trouve TOUS LES match -- retourne un array
notreModel.findOne() //trouve LE PREMIER match --retourne qu truc , je sais pas quoi
////Tester la DB avec MOCHA/////////////CHERCHER SUR LA DB///////////////////////////////////////////////////
//nodemon avec mocha, pour avoir un watch et un output leger et clean :
"test": "nodemon --exec 'mocha -R min'",
////Tester la DB avec MOCHA/////////////DELETE DE FICHE LA DB////////////////////////////////////////////
//TEST MOCHA -
const assert = require('assert');
const User = require('../src/user'); //notre model User. notre DB
//LIRE LA DB.
describe("DELETE une fiche user", () => {
//le but est de faire une fiche pour la tester, pour etre sur qu on a du data a lire.
let joe; //pour avoir acces en bas.
beforeEach((done) => {
joe = new User({name: 'Joe'}); //l instance se creer avec un id deja. et le name ..
joe.save() //save retourne un promisse ..
.then(() => done());
});
it('ici on remove avec instance de model (new)', (done) => {
joe.remove()
.then(() => {
return User.findOne({ name: "Joe"})
})
.then((user) => {
assert(user === null)
})
done()
});
it('ici on remove avec le model class directement', (done) => {
//remover un packet ou un des fiches, suivant un critiere.
User.remove({ name: "Joe"})
.then(() => {
return User.findOne({ name: "Joe"})
})
.then((user) => {
assert(user === null);
})
done()
});
it('ici on findOneAndRemove avec le model class directement', (done) => {
//remover un packet ou un des fiches, suivant un critiere.
User.findOneAndRemove({ name: "Joe"})
.then(() => {
return User.findOne({ name: "Joe"})
})
.then((user) => {
assert(user === null);
})
done();
});
it('ici on findByIdAndRemove avec le model class directement', (done) => {
User.findByIdAndRemove( joe._id )
.then(() => {
return User.findOne({ name: "Joe"})
})
.then((user) => {
assert(user === null);
})
done();
});
});
////Tester la DB avec MOCHA/////////////DELETE DE FICHE LA DB////////////////////////////////////////////
////Tester la DB avec MOCHA/////////////UPDATE DE FICHE LA DB////////////////////////////////////////////
//TEST MOCHA - polue la DB ..
const assert = require('assert');
const User = require('../src/user'); //notre model User. notre DB
//le nom revient toujours a joe au debut de chaque test. ***
describe('Updater une fiche user', () => {
let joe; //pour avoir acces en bas.
beforeEach((done) => {
joe = new User({name: 'Joe'}); //l instance se creer avec un id deja. et le name ..
joe.save() //save retourne un promisse ..
.then(() => done());
});
//FN POUR SAUVER LA REPETITION . //FN POUR SAUVER LA REPETITION . haha
function assertName(sauvegardeQuiRetourneUnePromisse, done){
sauvegardeQuiRetourneUnePromisse
.then(() => User.find({})) ///va retourner tout la db en array!!! avec ca on pourra scanner.
//maintenant qu'on peut scanner la db ... sinon on a pas acces a users, de la le 2 then.
.then((users) => {
assert(users.length === 1); //y en aura qu un
assert(users[0].name === 'AXE-Z'); //et maintenant il se nomme AXE-Z
done();
}).catch((err) => {
console.log(err)
});
}
//FN POUR SAUVER LA REPETITION . //FN POUR SAUVER LA REPETITION .
//AVEC l'instance //AVEC l'instance //AVEC l'instance //AVEC l'instance
it('Avec l\'instance le set et save', (done) => {
joe.set({name: 'AXE-Z'}); // ou ('name', 'AXE-Z') //juste setter ne change pas la db, dans la console oui, mais pas la db. il faut saver.
assertName(joe.save(), done()) //ou done pas de()
//done(); /// ou sans 2 ieme argument a
});
it('Avec l\'instance et UPDATE (qui sauvegarde tout seul)', (done) => {
assertName(joe.update({name: 'Ben'}), done()); //ou done pas de()
});
//AVEC l'instance //AVEC l'instance //AVEC l'instance //AVEC l'instance
//AVEC LE MODEL DIRECT*****//AVEC LE MODEL DIRECT*****//AVEC LE MODEL DIRECT*****
it('Avec le Model directement on update', (done) => {
assertName(User.update({name: 'Joe'}, {name: 'Bob'}), done());
});
it('Avec le Model directement update un seul user', (done) => {
assertName(User.findOneAndUpdate({name: 'Joe'}, {name: 'Axe-z'}), done());
});
//
it('Avec le Model directement AVEC UN ID et update un seul user', (done) => {
assertName(User.findByIdAndUpdate(joe._id, {name: 'Axe-z'}), done());
});
//AVEC LE MODEL DIRECT*****//AVEC LE MODEL DIRECT*****//AVEC LE MODEL DIRECT*****
}); ///describe end
//MAIS Y A UN ENORME FUCK AVEC UPDATE, il faut le savoir en sale, ca va updater que le premier. 1er arg , selection, 2ieme arg transformation, il faut un troisieme arg si on veut modifier plusieurs elements....
// donc options est le 3 ieme ... l option se nomme multi : true ou false ,
//COMMENT FAIRE
//set et save, sur l instance. est cool, permet de tout faire les modif, sur plusieurs chose, et seulement ensuite sauvegarder. Ce qui est moins demandant, et plus safe.
function peUpdateName(userInstance){
... MONGOOSE FAIT LE CHANGEMENT ET GARDE EN MEMOIRE
}
function peUpdateEmail(userInstance){
... MONGOOSE FAIT LE CHANGEMENT ET GARDE EN MEMOIRE
}
peUpdateName(userInstance);
peUpdateEmail(userInstance);
//donc on fait tout et ensuite , save.
userInstance.save();
///////////////////////// MONGO UPDATE OPERATOR///////////////////////////////////////////
///////////////////////////***** MONGO UPDATE OPERATOR == *****
///ce que c'est :
on peut le voir comme des snippets pour raccourcir considerablement certaines actions qui sont commune .
De faire des manipulations rapide, directement sans avoir a ramner le data et faire du code et renvoyer.
//https://docs.mongodb.com/manual/reference/operator/update/
//Update Operators
//Fields
//fantastique pour modifier PLUSIEURS item a la fois, pour un seul pas besoin de ca. un seul se fiat d une ligne d ordinaire avec update : assertName(User.update({name: 'Joe'}, {name: 'Bob'}), done());.
Name Description
$inc Increments the value of the field by the specified amount.
$mul Multiplies the value of the field by the specified amount.
$rename Renames a field.
$setOnInsert Sets the value of a field if an update results in an insert of a document. Has no effect on update operations that modify existing documents.
$set Sets the value of a field in a document.
$unset Removes the specified field from a document.
$min Only updates the field if the specified value is greater than the existing field value.
$max Only updates the field if the specified value is less than the existing field value.
$currentDate Sets the value of a field to current date, either as a Date or a Timestamp.
//Array
Name Description
$ Acts as a placeholder to update the first element that matches the query condition in an update.
$addToSet Adds elements to an array only if they do not already exist in the set.
$pop Removes the first or last item of an array.
$pullAll Removes all matching values from an array.
$pull Removes all array elements that match a specified query.
$pushAll Deprecated. Adds several items to an array.
$push Adds an item to an array.
//Modifier
Name Description
$each Modifies the $push and $addToSet operators to append multiple items pour array updates.
$slice Modifies the $push operator to limit the size of updated arrays.
$sort Modifies the $push operator to reorder documents stored in an array.
$position Modifies the $push operator to specify the position in the array to add elements.
//
//https://docs.mongodb.com/manual/reference/operator/update/
///////////////////////// MONGO UPDATE OPERATOR///////////////////////////////////////////
///////////////////////// MONGO QUERY OPERATOR///////////////////////////////////////////
Comparison
//https://docs.mongodb.com/manual/reference/operator/query/
For comparison of different BSON type values, see the specified BSON comparison order.
Name Description
$eq Matches values that are equal to a specified value.
$gt Matches values that are greater than a specified value.
$gte Matches values that are greater than or equal to a specified value.
$lt Matches values that are less than a specified value.
$lte Matches values that are less than or equal to a specified value.
$ne Matches all values that are not equal to a specified value.
$in Matches any of the values specified in an array.
$nin Matches none of the values specified in an array.
Logical
Name Description
$or Joins query clauses with a logical OR returns all documents that match the conditions of either clause.
$and Joins query clauses with a logical AND returns all documents that match the conditions of both clauses.
$not Inverts the effect of a query expression and returns documents that do not match the query expression.
$nor Joins query clauses with a logical NOR returns all documents that fail to match both clauses.
Element
Name Description
$exists Matches documents that have the specified field.
$type Selects documents if a field is of the specified type.
Evaluation
Name Description
$mod Performs a modulo operation on the value of a field and selects documents with a specified result.
$regex Selects documents where values match a specified regular expression.
$text Performs text search.
$where Matches documents that satisfy a JavaScript expression.
Name Description
$geoWithin Selects geometries within a bounding GeoJSON geometry. The 2dsphere and 2d indexes support $geoWithin.
$geoIntersects Selects geometries that intersect with a GeoJSON geometry. The 2dsphere index supports $geoIntersects.
$near Returns geospatial objects in proximity to a point. Requires a geospatial index. The 2dsphere and 2d indexes support $near.
$nearSphere Returns geospatial objects in proximity to a point on a sphere. Requires a geospatial index. The 2dsphere and 2d indexes support $nearSphere.
Array
Name Description
$all Matches arrays that contain all elements specified in the query.
$elemMatch Selects documents if element in the array field matches all the specified $elemMatch conditions.
$size Selects documents if the array field is a specified size.
Bitwise
Name Description
$bitsAllSet Matches numeric or binary values in which a set of bit positions all have a value of 1.
$bitsAnySet Matches numeric or binary values in which any bit from a set of bit positions has a value of 1.
$bitsAllClear Matches numeric or binary values in which a set of bit positions all have a value of 0.
$bitsAnyClear Matches numeric or binary values in which any bit from a set of bit positions has a value of 0.
Comments
Name Description
$comment Adds a comment to a query predicate.
///////////////////////// MONGO QUERY OPERATOR///////////////////////////////////////////
//////////////////Projection Operators //////////////////
Name Description
$ Projects the first element in an array that matches the query condition.
$elemMatch Projects the first element in an array that matches the specified $elemMatch condition.
$meta Projects the document’s score assigned during $text operation.
$slice Limits the number of elements projected from an array. Supports skip and limit slices.
///////////////////////// MONGOOSE ///////////////////////////////////////////
//CE qu on a fait pour l instant, n utilisait pas la force de mongoose et on aurait presque pu le faire sans=>
mais mongoose est plus puissant que ca , et donne entre autre acces a de la validation .
///DANS LE MODEL
const UserSchema = new Schema({ ///forme de la schema
name: {
type: String,
// trim: true,
validate: {
validator: (name) => name.length > 2,
message: 'Doit avoir plus de 2 caracteres'
},
required: [true, 'Name is required'] //fait jsute regarder si y a quelque chose..
},
postCount: Number
});
///dnas le test de mocha :
const assert = require('assert');
const User = require('../src/user'); //notre model User. notre DB
//validateSync: fn de mongoose, est comme validate, mais Synchronious.
describe('VALIDER une fiche user', () => {
//test directement avec mongoose
it('Il doit y avoir un User Name', () => {
const user = new User({name: undefined}) //pour tester clairement.
const validationResult = user.validateSync(); //validate est async , validateSync est sync
// console.log(validationResult) //pour voir l erreure
const { message } = validationResult.errors.name; // le message de mongooe sera la. deconstruction
assert(message === 'Name is required');
});
//le message sera lui dans le model, lui de validator dans user.js:
// validate: {
// validator: (name) => name.length > 2,
// message: 'Doit avoir plus de 2 caracteres'
// },
///test avec le model.
it('Plus de 3 caracteres dans le nom', () => {
const user = new User({name: 'Al'});
const validationResult = user.validateSync();
const { message } = validationResult.errors.name;
assert(message === 'Doit avoir plus de 2 caracteres');
});
});
/////////////////////////ajouter un schema subdocument///////////////////////////////////////////
//dans post.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const PostSchema = new Schema({
titre: String
});
module.exports = PostSchema; //exporte cette sub schema.
//dans user.js
const mongoose = require('mongoose');
const PostSchema = require('./post'); ///nouvel schema
const Schema = mongoose.Schema;
//faire le plus de menage possible a la base
const UserSchema = new Schema({ ///forme de la schema
name: {
type: String,
// trim: true,
validate: {
validator: (name) => name.length > 2,
message: 'Doit avoir plus de 2 caracteres'
},
required: [true, 'Name is required'] //fait jsute regarder si y a quelque chose..
},
postCount: Number,
posts: [ PostSchema ] ///va faire la magie !
});
//on appelle ca sub-document, une schema qui s' ajoute a une autre dans le MEME MODEL.
//lui decide de le faire dnas un autre fichier et de l importer ici. donc post.js
// const PostSchema = new Schema({
// title: String
// });
const User = mongoose.model('user', UserSchema) //le model pour mongo la dessus son les methode.
//console.log(User)
/////////////////////////Vitual fields///////////////////////////////////////////
// on veut ici que le nombre de posts soit representé dasn postCount et que ce chiffre se fasse seul.:
//donc on sert postCount de la schema, et l ajoute ici:
UserSchema.virtual('postCount').get(function (){
return this.posts.length; //donne la qte de posts.
});
//Champ virtuel ! la valeur de postCount sera le lenght de titre qu on aura.
//fonctionne avec es6 getter et setter. joe.postCount va devenir une genre de function qui va aller chercher l info sur le fly. doit utiliser function pas de arrow dans le getter. on a besoin du this, le this devient l isntance qui appele postcount. donc joe.postCount , this === joe.
/////////////////////////Vitual fields///////////////////////////////////////////
/////////////////////////////////////////joindre trois models ///////////////////////////////////
const UserSchema = new Schema({ ///forme de la schema
name: {
type: String,
validate: {
validator: (name) => name.length > 2,
message: 'Doit avoir plus de 2 caracteres'
},
required: [true, 'Name is required'] //fait jsute regarder si y a quelque chose..
},
posts: [ PostSchema ], ///va faire la magie pour un subdocument!
likes: Number,
blogPosts: [{
type: Schema.Types.ObjectId,
ref: 'blogPost' //en lien avec le model blogPost
}]
});
const BlogPostSchema = new Schema({
titre: String,
content: String,
comments: [{
type: Schema.Types.ObjectId,
ref: 'comment' //en lien avec le model comment
}]
});
const CommentSchema = new Schema({ ///forme de la schema
content: String,
user: {
type: Schema.Types.ObjectId,
ref: 'user' //en lien avec le model user
}
});
en test maintenant apres les avoir importé.
describe('Assocations', () => {
let joe, blogPost, comment;
beforeEach((done) => {
joe = new User({ name: 'Joe' });
blogPost = new BlogPost({ titre: 'JS is Great', content: 'Yep it really is' });
comment = new Comment({ content: 'Congrats on great post' });
joe.blogPosts.push(blogPost); ///ARR
blogPost.comments.push(comment); ///ARR
comment.user = joe; ///OBJ
Promise.all([joe.save(), blogPost.save(), comment.save()])
.then(() => done());
});
/* IMPORTANT
!!! ameliorer nos query avec un modifier. Avec POPULATE , User.findOne({ name: 'Joe' }) .populate('blogPosts')
veut dire : load le user joe, et retourne le user avec tous les blogposts qui lui sont associer.
*/
it('saves a relation between a user and a blogpost', (done) => {
User.findOne({ name: 'Joe' })
.populate('blogPosts') //IMPORTANT
.then((user) => {
assert(user.blogPosts[0].titre === 'JS is Great');
done();
});
});
it('saves a full relation graph', (done) => {
User.findOne({ name: 'Joe' })
.populate({
path: 'blogPosts',
populate: {
path: 'comments',
model: 'comment',
populate: {
path: 'user',
model: 'user'
}
}
})
.then((user) => {
assert(user.name === 'Joe');
assert(user.blogPosts[0].titre === 'JS is Great');
assert(user.blogPosts[0].comments[0].content === 'Congrats on great post');
assert(user.blogPosts[0].comments[0].user.name === 'Joe');
done();
});
});
});
DONC :
populate : peut prendre un obj comme configuration
path : dans ce user, on veut aussi cette info.
//console.log(user.blogPosts[0].comments[0].user) on pourrait faire une roue infinie :
//user.blogPosts[0].comments[0].user.blogPosts[0].comments[0].user.blogPosts[0].comments[0].user ...
User.findOne({ name: 'Joe' //va chercher le user
.populate({
path: 'blogPosts', //va chercher les blogPosts de ce user
populate: { ///deuxieme etapes de creusage
path: 'comments', //va dans les blogPosts de ce user chercher les comments
model: 'comment', //il faut dire dans quel model il doit chercher ca.
populate: {
path: 'user', //va dans les blogPosts de ce user chercher les comments et de qui il sont
model: 'user' //il faut aussi ici dire dans quel model il doit chercher ca.
}
}
})
.then(user => {
console.log(user.blogPosts[0].comments[0]/*.user.blogPosts[0]*/)
assert(user.name === "Joe");
assert(user.blogPosts[0].titre === "JS est cool");
assert(user.blogPosts[0].comments[0].content === "Congrats on great post");
assert(user.blogPosts[0].comments[0].user.name === "Joe"); ///tout un tour...
done();
});
MIDDLEWARE
//////////////////////RElation si le user est detruit, comment effacer le reste des trucs associees////////////
//comment deleter les trucs associer avec le middleware.
IL Y A 2 TYPE DE MIDDLEWARE, CEUX PRE EVENT ET CEUX POST EVENT..
DISONS SAVE() EST UN EVENT . DONC ON POURRAIT ROULER deux MIDDLEWARES AVANT LE SAVE ET UN APRES .
ou REMOVE() dans le cas qui nous interesse
///middleware
UserSchema.pre('remove', function (){
//pour avoir au this,,,
});
//////////////////////RElation si le user est detruit, middleware suite ////////////
// le probleme est de ne pas avoir a importer dans User.js les deux autre page et vice versa, enfaisant un loop d improtation, si jamais on avait des pre ou post pour chaque model.
// y a moyen d acceder aux modelk sans importation, une fois les model linker a mongoose, il sont disponnible dans la collection.
///middleware et query OPERATOR // fn a besoin de next pour passer la main.
UserSchema.pre('remove', function (next){
const BlogPost = mongoose.model('BlogPost');
// $in regarde dans this.blogPosts tous ceux qui match avec le _id en question.
BlogPost.remove({_id: { $in: this.blogPosts}}) //retourne un promise.
.then( () => next()); // ca continue..
});
///tester ca
describe('Middleware', () => {
let joe, blogPost;
///mettre du contenu dans la DB.
beforeEach((done) => {
joe = new User({ name: 'Joe' });
blogPost = new BlogPost({ titre: 'JS est cool', content: 'Yep it really is' });
joe.blogPosts.push(blogPost);
Promise.all([joe.save(), blogPost.save()])
.then(() => done());
});