mongoDB.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. import mongoose from 'mongoose';
  2. const {Schema, connect, model: _model} = mongoose;
  3. const defaultOptions = {useNewUrlParser: true, useUnifiedTopology: true};
  4. export class mongoDB {
  5. constructor(url, options = defaultOptions) {
  6. /**
  7. * @type {string}
  8. */
  9. this.url = url;
  10. /**
  11. * @type {mongoose.ConnectOptions}
  12. */
  13. this.options = options;
  14. this.data = this._data = {};
  15. /**
  16. * @type {mongoose.Schema}
  17. */
  18. this._schema = {};
  19. /**
  20. * @type {mongoose.Model}
  21. */
  22. this._model = {};
  23. /**
  24. * @type {Promise<typeof mongoose>}
  25. */
  26. this.db = connect(this.url, {...this.options}).catch(console.error);
  27. }
  28. async read() {
  29. this.conn = await this.db;
  30. const schema = this._schema = new Schema({
  31. data: {
  32. type: Object,
  33. required: true, // depends on whether the field is mandatory or not
  34. default: {},
  35. },
  36. });
  37. try {
  38. this._model = _model('data', schema);
  39. } catch {
  40. this._model = _model('data');
  41. }
  42. this._data = await this._model.findOne({});
  43. if (!this._data) {
  44. this.data = {};
  45. const [_, _data] = await Promise.all([
  46. this.write(this.data),
  47. this._model.findOne({}),
  48. ]);
  49. this._data = _data;
  50. } else this.data = this._data.data;
  51. return this.data;
  52. }
  53. write(data) {
  54. return new Promise(async (resolve, reject) => {
  55. if (!data) return reject(data);
  56. if (!this._data) return resolve((new this._model({data})).save());
  57. this._model.findById(this._data._id, (err, docs) => {
  58. if (err) return reject(err);
  59. if (!docs.data) docs.data = {};
  60. docs.data = data;
  61. this.data = {};
  62. return docs.save(resolve);
  63. });
  64. });
  65. }
  66. }
  67. export const mongoDBV2 = class MongoDBV2 {
  68. constructor(url, options = defaultOptions) {
  69. /**
  70. * @type {string}
  71. */
  72. this.url = url;
  73. /**
  74. * @type {mongoose.ConnectOptions}
  75. */
  76. this.options = options;
  77. /**
  78. * @type {{ name: string, model: mongoose.Model}[]}
  79. */
  80. this.models = [];
  81. /**
  82. * @type {{ [Key: string]: any }}
  83. */
  84. this.data = {};
  85. this.lists;
  86. /**
  87. * @type {mongoose.Model}
  88. */
  89. this.list;
  90. /**
  91. * @type {Promise<typeof mongoose>}
  92. */
  93. this.db = connect(this.url, {...this.options}).catch(console.error);
  94. }
  95. async read() {
  96. this.conn = await this.db;
  97. const schema = new Schema({
  98. data: [{
  99. name: String,
  100. }],
  101. });
  102. try {
  103. this.list = _model('lists', schema);
  104. } catch (e) {
  105. this.list = _model('lists');
  106. }
  107. this.lists = await this.list.findOne({});
  108. if (!lists?.data) {
  109. await this.list.create({data: []});
  110. // await (new this.list({ data: [] })).save()
  111. this.lists = await this.list.findOne({});
  112. }
  113. const garbage = [];
  114. for (const {name} of this.lists.data) { // get data from list
  115. /**
  116. * @type {mongoose.Model}
  117. */
  118. let collection;
  119. try {
  120. collection = _model(name, new Schema({data: Array}));
  121. } catch (e) {
  122. console.error(e);
  123. try {
  124. collection = _model(name);
  125. } catch (e) {
  126. garbage.push(name);
  127. console.error(e);
  128. }
  129. }
  130. if (collection) {
  131. this.models.push({name, model: collection});
  132. const collectionsData = await collection.find({});
  133. this.data[name] = Object.fromEntries(collectionsData.map((v) => v.data));
  134. }
  135. }
  136. try {
  137. // Delete list if not exist
  138. const del = await this.list.findById(this.lists._id);
  139. del.data = del.data.filter((v) => !garbage.includes(v.name));
  140. await del.save();
  141. } catch (e) {
  142. console.error(e);
  143. }
  144. return this.data;
  145. }
  146. write(data) {
  147. return new Promise(async (resolve, reject) => {
  148. if (!this.lists || !data) return reject(data || this.lists);
  149. const collections = Object.keys(data); const listDoc = []; let index = 0;
  150. for (const key of collections) {
  151. // Update if exist
  152. if ((index = this.models.findIndex((v) => v.name === key)) !== -1) {
  153. const doc = this.models[index].model;
  154. await doc.deleteMany().catch(console.error); // alwasy insert, no matter delete error
  155. await doc.insertMany(Object.entries(data[key]).map((v) => ({data: v})));
  156. if (doc && key) listDoc.push({name: key});
  157. } else { // if not exist, create new model
  158. const schema = new Schema({
  159. data: Array,
  160. });
  161. /**
  162. * @type {mongoose.Model}
  163. */
  164. let doc;
  165. try {
  166. doc = _model(key, schema);
  167. } catch (e) {
  168. console.error(e);
  169. doc = _model(key);
  170. }
  171. index = this.models.findIndex((v) => v.name === key);
  172. this.models[index === -1 ? this.models.length : index] = {name: key, model: doc};
  173. await doc.insertMany(Object.entries(data[key]).map((v) => ({data: v})));
  174. if (doc && key) listDoc.push({name: key});
  175. }
  176. }
  177. // save list
  178. this.list.findById(this.lists._id, function(err, doc) {
  179. if (err) return reject(err);
  180. doc.data = listDoc;
  181. this.data = {};
  182. return doc.save(resolve);
  183. });
  184. return resolve(true);
  185. });
  186. }
  187. };