-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
626 lines (626 loc) · 43.5 KB
/
index.html
File metadata and controls
626 lines (626 loc) · 43.5 KB
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
<!doctype html>
<html class="default no-js">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>tedb</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="assets/css/main.css">
</head>
<body>
<header>
<div class="tsd-page-toolbar">
<div class="container">
<div class="table-wrap">
<div class="table-cell" id="tsd-search" data-index="assets/js/search.js" data-base=".">
<div class="field">
<label for="tsd-search-field" class="tsd-widget search no-caption">Search</label>
<input id="tsd-search-field" type="text" />
</div>
<ul class="results">
<li class="state loading">Preparing search index...</li>
<li class="state failure">The search index is not available</li>
</ul>
<a href="index.html" class="title">tedb</a>
</div>
<div class="table-cell" id="tsd-widgets">
<div id="tsd-filter">
<a href="#" class="tsd-widget options no-caption" data-toggle="options">Options</a>
<div class="tsd-filter-group">
<div class="tsd-select" id="tsd-filter-visibility">
<span class="tsd-select-label">All</span>
<ul class="tsd-select-list">
<li data-value="public">Public</li>
<li data-value="protected">Public/Protected</li>
<li data-value="private" class="selected">All</li>
</ul>
</div>
<input type="checkbox" id="tsd-filter-inherited" checked />
<label class="tsd-widget" for="tsd-filter-inherited">Inherited</label>
<input type="checkbox" id="tsd-filter-externals" checked />
<label class="tsd-widget" for="tsd-filter-externals">Externals</label>
<input type="checkbox" id="tsd-filter-only-exported" />
<label class="tsd-widget" for="tsd-filter-only-exported">Only exported</label>
</div>
</div>
<a href="#" class="tsd-widget menu no-caption" data-toggle="menu">Menu</a>
</div>
</div>
</div>
</div>
<div class="tsd-page-title">
<div class="container">
<ul class="tsd-breadcrumb">
<li>
<a href="globals.html">Globals</a>
</li>
</ul>
<h1> tedb</h1>
</div>
</div>
</header>
<div class="container container-main">
<div class="row">
<div class="col-8 col-content">
<div class="tsd-panel tsd-typography">
<h1 id="-tedb-https-github-com-tsturzl-tedb-"><a href="https://github.com/tsturzl/teDB">TeDB</a></h1>
<p>A TypeScript Embedded Database. A structure sane embedded database with <a href="https://tedb-org.github.io/#writing-a-storage-driver-for-tedb">pluggable storage</a> and clean concise <a href="https://tedb-org.github.io/">documentation</a>.</p>
<h2 id="install">Install</h2>
<pre><code class="lang-bash">npm install --save tedb
</code></pre>
<h2 id="resources-">Resources:</h2>
<ul>
<li><a href="https://tedb-org.github.io/">API Documentation</a></li>
</ul>
<h2 id="usage">Usage</h2>
<p>TeDB uses an AVL balanced binary tree <a href="https://github.com/marcusjwhelan/binary-type-tree">binary-type-tree</a> to save indexed fields of documents. TeDB does not save documents to memory or have a set way of saving data. It is hooked up to a storage driver that can either work to persists data to disk or save data to memory. The binary tree only saves the value and _id to memory allowing for larger data sets to be indexed. </p>
<p>Almost all operations use a method of the storage driver to save, delete, or search, for documents. This is why a robust storage driver is needed more specifically fit your needs. Feel free to write your own storage driver and possibly have it mentioned below for others to use. TeDB is almost completely Promise based and you can expect each method to return a promise, even if the return is null or never. A large benefit to using TeDB is it is written 100% in Typescript. Except for one javascript preprocessor for Jest. </p>
<pre><code class="lang-typescript"><span class="hljs-comment">// ES6 options</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> tedb <span class="hljs-keyword">from</span> <span class="hljs-string">"tedb"</span>;
<span class="hljs-keyword">import</span> { Datastore, IDatastore, Cursor, Ioptions, IindexOptions,
IupdateOptions, Index, IIndex, IStorageDriver, IRange, range,
isEmpty, getDate, compareArray, rmObjDups, getPath, Base64,
expandObj, compressObj, flatten, saveArrDups, getDups, rmArrDups} <span class="hljs-keyword">from</span> <span class="hljs-string">"tedb"</span>;
<span class="hljs-comment">// ES5 options</span>
<span class="hljs-keyword">var</span> tedb = <span class="hljs-built_in">require</span>(<span class="hljs-string">"tedb"</span>);
<span class="hljs-keyword">var</span> Datastore = <span class="hljs-built_in">require</span>(<span class="hljs-string">"tedb"</span>).Datastore;
</code></pre>
<h2 id="writing-a-storage-driver-for-tedb">Writing a storage driver for TeDB</h2>
<p>There is a very simple example of a NodeJS storage driver in the <code>/spec/example</code> directory that is used for the testing of the datastore. You can also see an example of what a data store preferably should look like from your storage driver for nodejs in the <code>/spec/fixtures/db</code> directory. When creating a storage driver that persists to a filesystem for FAT32, NTFS, ext2, ext3, and ext4 most directories use a binary tree store the location of the file. So utilizing this it is faster to query the file instead of having to create another binary tree to hold the location of a document in a file. <a href="https://stackoverflow.com/questions/466521/how-many-files-can-i-put-in-a-directory">source</a>. </p>
<p>This however is not always the case and this is why many different storage drivers are needed for more specific situations where possibly on mobile this is not the best option. But for these other file systems you could have a datastore with around 4.3 billion documents. With each database capable of 4.3 billion datastores. This of course is dependant on the storage driver you create and the way in which the storage driver saves its data. </p>
<p>Memory only storage drivers could utilize other in memory databases such as indexedDB. I would be on the lookout for in memory javascript databases because this project was started in the response to other javascript embedded databases indexing entire documents for speed. This can with a large enough database overload your memory and bring your application to a halt.</p>
<h2 id="storage-drivers">Storage drivers</h2>
<ul>
<li><a href="">Example Link </a></li>
</ul>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#usage">Usage</a></li>
<li><a href="#writing-a-storage-driver-for-tedb">Writing a storage driver for TeDB</a></li>
<li><a href="#creating-a-datastore">Creating a Datastore</a></li>
<li><a href="#indexing">Indexing</a></li>
<li><a href="#inserting">Inserting</a></li>
<li><a href="#findcount-and-get-date-from-_id">Find/Count and Get Date from _id</a></li>
<li><a href="#update">Update</a></li>
<li><a href="#remove">Remove</a></li>
<li><a href="#utilities">Utilities</a></li>
<li><a href="#license">License</a></li>
</ul>
<h2 id="creating-a-datastore">Creating a Datastore</h2>
<p>Each database will consist of however many datastores you would like to create. Depending on your storage driver your datastores will save data differently but to simply create a datastore you only need to connect an instance of the storage driver to an instance of a new Datastore. The storage driver represented in this example is a pointer to any storage driver you decide to use, "yourStorageDriverClass".</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> tedb <span class="hljs-keyword">from</span> <span class="hljs-string">"tedb"</span>;
<span class="hljs-comment">// For example, I want to make Users</span>
<span class="hljs-keyword">const</span> UserStorage = <span class="hljs-keyword">new</span> yourStorageDriverClass(<span class="hljs-string">"users"</span>);
<span class="hljs-keyword">const</span> Users = <span class="hljs-keyword">new</span> tedb.DataStore({storage: UserStorage});
</code></pre>
<p>For the storage driver it should have the methods found on the storage driver interface found <a href="https://github.com/tsturzl/teDB/blob/master/src/types/storageDriver.ts">here</a>. Now that you have the datastore created you can insert and query on those inserted items. Each item inserted has an automatic <code>_id</code> generated for them. This <code>_id</code> also saves the created on Date. The <code>_id</code>s are not indexed automatically but can be if you decide to.</p>
<h2 id="indexing">Indexing</h2>
<p>Indices are saved as a Map on the Datastore class for each property. When you create an index on a property you give the path of the index and then the options of that index. Indices are stored as a key, value store with the key being the value given i.e. the actual username. And where the value of the key value storey is actually the _id of the object. <code>_id</code>s are created each time you insert an object into TeDB. The values of the key value store are always arrays. <code>{ "myUserNameValue": ["_idofobject"]}</code> if the index is not unique then the value is still an array except for each matching key the new ids are added. <code>{ "actualAge#": ["_id1", "_id2", "_id3"]}</code>.</p>
<ul>
<li>Index Options<ul>
<li>fieldName - The path as a string <code>"path.to.index"</code> to be indexed on the object</li>
<li>unique - Set value to have a unique restriction or not</li>
<li>checkKeyEquality - You can pass your own equality check method: <a href="https://github.com/marcusjwhelan/binary-type-tree/blob/master/src/bTreeUtils.ts#L92">Default</a></li>
<li>compareKeys - You can pass your own method to compare keys: <a href="https://github.com/marcusjwhelan/binary-type-tree/blob/master/src/bTreeUtils.ts#L44">Default</a><pre><code class="lang-typescript"><span class="hljs-comment">// Create Index</span>
<span class="hljs-comment">// Returns a promise of null</span>
<span class="hljs-keyword">return</span> Users.ensureIndex({fieldName: <span class="hljs-string">"username"</span>, unique: <span class="hljs-literal">true</span>});
</code></pre>
</li>
</ul>
</li>
</ul>
<p>If you ever need to use some of the other index methods such as <code>insertIndex</code>, <code>removeIndex</code>, or <code>saveIndex</code> the <code>getIndices</code> will be needed. <strong>DS stands for Datastore</strong> and <strong>SD for Storage Driver</strong>.</p>
<ul>
<li>getIndices: <strong>DS</strong> - returns a promise containing the index map of this datastore</li>
<li>saveIndex: <strong>DS</strong> - saves a JSON representation of the index using the storage driver</li>
<li>removeIndex: <strong>DS</strong> - Removes the index from the datastore - does not delete index from storage driver automatically. If you want to remove the index from storage use the storage driver's removeIndex method.</li>
<li>insertIndex: <strong>DS</strong> - Insert a JSON representation of an index into this datastore's index Map.</li>
<li>removeIndex: <strong>SD</strong> - Should delete the location of the stored index, dependent on the SD method.</li>
<li>fetchIndex: <strong>SD</strong> - Should return the <strong>parsed</strong> index from storage</li>
<li>storeIndex: <strong>SD</strong> - Should save the index</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-comment">// I am assuming all success</span>
<span class="hljs-comment">// Create an index and store it - can create nested index -> "nested.index.path" instead of "age"</span>
Users.ensureIndex({fieldName: <span class="hljs-string">"age"</span>})
.then(<span class="hljs-function"><span class="hljs-params">()</span> =></span> {
<span class="hljs-keyword">return</span> <span class="hljs-comment">// insert several documents so the bTree is filled</span>
})
.then(<span class="hljs-function"><span class="hljs-params">()</span> =></span> {
<span class="hljs-comment">// converts index to json and saves using storage driver</span>
<span class="hljs-comment">// storeIndex method, returns a promise of whatever the storage driver</span>
<span class="hljs-comment">// returns. </span>
<span class="hljs-keyword">return</span> Users.saveIndex(<span class="hljs-string">"age"</span>);
})
.then(<span class="hljs-comment">/** success */</span>)
.catch();
<span class="hljs-comment">//</span>
<span class="hljs-comment">// On start up you might want to load the saved index to skip creating the btree for</span>
<span class="hljs-comment">// each datastore, this should save load times of applications.</span>
<span class="hljs-keyword">let</span> index: <span class="hljs-built_in">any</span>[];
UserStorage.fetchIndex(<span class="hljs-string">"age"</span>)
.then(<span class="hljs-function">(<span class="hljs-params">indexArray</span>) =></span> {
index = indexArray;
<span class="hljs-comment">// need to insert the index into the current datastore</span>
<span class="hljs-keyword">return</span> Users.ensureIndex({fieldName: <span class="hljs-string">"age"</span>});
})
.then(<span class="hljs-function"><span class="hljs-params">()</span> =></span> {
<span class="hljs-keyword">return</span> Users.insertIndex(<span class="hljs-string">"age"</span>, index);
})
.then(<span class="hljs-comment">/** success */</span>)
.catch();
<span class="hljs-comment">//</span>
<span class="hljs-comment">// Search an index manually</span>
Users.getIndices()
.then(<span class="hljs-function">(<span class="hljs-params">indices</span>) =></span> {
<span class="hljs-keyword">const</span> IndexName = indices.get(<span class="hljs-string">"age"</span>);
<span class="hljs-keyword">if</span> (IndexName) {
<span class="hljs-keyword">return</span> IndexName.search(<span class="hljs-number">32</span>);
}
})
.then(<span class="hljs-function">(<span class="hljs-params">ids</span>) =></span> {
<span class="hljs-keyword">return</span> UserStorage.getItem(ids[<span class="hljs-number">0</span>]);
})
.then(<span class="hljs-function">(<span class="hljs-params">user</span>) =></span> { <span class="hljs-comment">/** success */</span>})
.catch();
<span class="hljs-comment">//</span>
<span class="hljs-comment">// Remove Index from datastore and from storage</span>
Users.removeIndex(<span class="hljs-string">"age"</span>)
.then(<span class="hljs-function"><span class="hljs-params">()</span> =></span> {
<span class="hljs-keyword">return</span> UserStorage(<span class="hljs-string">"age"</span>);
})
.then(<span class="hljs-function"><span class="hljs-params">()</span> =></span> { <span class="hljs-comment">/** success */</span>})
.catch();
</code></pre>
<h2 id="inserting">Inserting</h2>
<p>Inserting a document is rather simple and dependent on your indices if you are able to insert a document or not. Depending on indexed fields the insert will fail if for instance a field is indexed, unique, and an array. If you did not specify a special array comparison method fo the index then the insert will fail because the default comparison method only compares strings, numbers, and Dates.</p>
<pre><code class="lang-typescript">Users.insert({name: <span class="hljs-string">"xyz"</span>, age: <span class="hljs-number">30</span>})
.then(<span class="hljs-function">(<span class="hljs-params">doc</span>) =></span> {
<span class="hljs-built_in">console</span>.log(doc) <span class="hljs-comment">// {_id: "...", name: "xyz", age: 30} </span>
})
.catch();
<span class="hljs-comment">// Insert many</span>
<span class="hljs-keyword">const</span> docs: <span class="hljs-built_in">any</span>[] = insertables; <span class="hljs-comment">// your array of documents</span>
<span class="hljs-keyword">const</span> promises: <span class="hljs-built_in">Array</span><<span class="hljs-built_in">Promise</span><<span class="hljs-built_in">any</span>>> = [];
docs.forEach(<span class="hljs-function">(<span class="hljs-params">doc</span>) =></span> {
promises.push(Users.insert(doc));
});
<span class="hljs-built_in">Promise</span>.all(promises)
.then(<span class="hljs-function"><span class="hljs-params">()</span> =></span> { <span class="hljs-comment">/** success */</span> })
.catch();
</code></pre>
<h2 id="find-count-and-get-date-from-_id">Find/Count and Get Date from _id</h2>
<p>Find uses a cursor class to work through a query object. Find always returns an array.</p>
<ul>
<li>Cursor Options<ul>
<li>sort - Sort by field {fieldName: -1 } or {fieldName: 1 }</li>
<li>skip - Skip a certain number of returned items </li>
<li>limit - Set a limit to max number of items returned</li>
<li>exec - execute the search using the cursor options, will search for all docs based on query before applying the sort, skip, or limit methods on them. </li>
</ul>
</li>
</ul>
<p>The find method actually will search through all the documents queried by either the index if indexed or by a collection search if not indexed. In the storage driver when documents are inserted, or removed their should be a keys array holding the keys of all the documents inserted just in case a field is searched without a query. If you search with an empty query the <strong>keys</strong> method of the storage driver is used that should return all the _ids of the datastore instead of having to retrieve all the keys from the storage driver memory/drive. </p>
<p>If you would rather not store memory for each _id inserted then use a storage driver that does not use the keys() method and you will not be able to search without a query.</p>
<ul>
<li>Find query options<ul>
<li>$or - search an object query of one <strong>or</strong> multiple</li>
<li>$and - search an object with <strong>and</strong> results or multiple</li>
<li>$gt, $lt, $gte, $lte, $ne - can combine any assortment.</li>
</ul>
</li>
</ul>
<p>Nesting queries is now supported but only in $and or $or. Cannot nest value inside $gt.. query options. No nesting $and or $or inside one another.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Example of nesting</span>
Users.find({$and: [
{age: {$gt: <span class="hljs-number">25</span>}},
{age: {$ne: <span class="hljs-number">28</span>}},
{age: {$lte: <span class="hljs-number">35</span>}},
]}).exec()
.then(resolve)
.catch(reject);
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// simple find</span>
Users.find({name: <span class="hljs-string">"xyz"</span>})
.exec()
.then(<span class="hljs-function">(<span class="hljs-params">docs</span>) =></span> {
<span class="hljs-built_in">console</span>.log(dos[<span class="hljs-number">0</span>]); <span class="hljs-comment">// {_id: "...", name: "xyz", age: 30}</span>
});
<span class="hljs-comment">// find all</span>
Users.find()
.exec()
.then(<span class="hljs-function">(<span class="hljs-params">docs</span>) =></span> {
<span class="hljs-built_in">console</span>.log(docs.length); <span class="hljs-comment">// length of all docs</span>
});
<span class="hljs-comment">// $or</span>
Users.find({$or: [{age: <span class="hljs-number">0</span>}, {name: <span class="hljs-number">30</span>}]})
.exec()
.then(<span class="hljs-comment">/** success */</span>);
<span class="hljs-comment">// $and</span>
Users.find({$and: [{name: <span class="hljs-string">"Francis"</span>}, {name: <span class="hljs-string">"xyz"</span>}]})
.exec()
.then(<span class="hljs-comment">/** success*/</span>);
<span class="hljs-comment">// find all with all cursor options</span>
Users.find({}) <span class="hljs-comment">// can also send empty object</span>
.sort({age: <span class="hljs-number">-1</span>})
.skip(<span class="hljs-number">1</span>)
.limit(<span class="hljs-number">1</span>)
.exec()
.then(<span class="hljs-function">(<span class="hljs-params">docs</span>) =></span> {
<span class="hljs-built_in">console</span>.log(docs.length); <span class="hljs-comment">// 1</span>
});
<span class="hljs-comment">// Search Nested</span>
Users.find({<span class="hljs-string">"nested.age.path"</span>: {$gte: <span class="hljs-number">0</span>, $lte: <span class="hljs-number">31</span>}})
.exec()
.then(<span class="hljs-function">(<span class="hljs-params">docs</span>) =></span> <span class="hljs-comment">/** success */</span>);
<span class="hljs-comment">// COUNT</span>
<span class="hljs-comment">// count uses the same query searching capabilities as find except only returns the number of docs</span>
Users.count({})
.exec()
.then(<span class="hljs-function">(<span class="hljs-params">num</span>) =></span> {
<span class="hljs-built_in">console</span>.log(num); <span class="hljs-comment">// total docs as a number</span>
});
<span class="hljs-comment">//</span>
<span class="hljs-comment">// If you would like to find an object that happens to have</span>
<span class="hljs-comment">// no index or _id/lets say you removed the _id by accident.</span>
<span class="hljs-keyword">const</span> doc = {<span class="hljs-comment">/* exact doc match you want to find */</span>};
<span class="hljs-keyword">const</span> target = {};
compressObj(doc, target);
Users.find(target)
.then(resolve)
.catch(reject);
</code></pre>
<p>TeDB also stores the time inserted.</p>
<pre><code class="lang-typescript">Users.find()
.exec()
.then(<span class="hljs-function">(<span class="hljs-params">docs</span>) =></span> {
<span class="hljs-comment">// example _id = "UE9UQVJWd0JBQUE9cmZ4Y2MxVzNlOFk9TXV4dmJ0WU5JUFk9d0FkMW1oSHY2SWs9"</span>
<span class="hljs-keyword">const</span> createdAt = Users.getIdDate(docs[<span class="hljs-number">0</span>]._id);
<span class="hljs-built_in">console</span>.log(createdAt); <span class="hljs-comment">// Date Object -> 2017-05-26T17:14:48.252Z</span>
})
</code></pre>
<h2 id="update">Update</h2>
<p>Update uses find to retrieve the objects and the storage driver to write back the changes if any need to be done. All update operations update the index as well if one exists. Although it does not update the stored JSON index. You must update that yourself by overwriting the old stored index. </p>
<ul>
<li>Update Options<ul>
<li>multi - return many documents: Default false</li>
<li>upsert - insert the document if not found: Default false, creates _id on insert</li>
<li>returnUpdatedDocs - returns all the docs after being updated and stored.</li>
<li>exactObjectFind - when finding objects search based on the exact object itself. Cannot use find queries such as $gt, $lt. Best used with updating an object completely if anything changes.</li>
</ul>
</li>
<li>Update Operators<ul>
<li>$set - write, overwrite a value to the document/s that are returned. Warning Cannot create an object from undefined.</li>
<li>$mul - multiply the value with the given query value</li>
<li>$inc - increment a positive or negative number to the value of the document</li>
<li>$unset - delete the value from the object</li>
<li>$rename - rename the key of a document, logically uses $unset then $set saving the value to memory in between.
You can work all the update options together, dependent on order.</li>
</ul>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-comment">// original object {_id: "...", name: "xyz"}</span>
<span class="hljs-comment">// query, operators, options</span>
Users.update({name: <span class="hljs-string">"xyz"</span>}, {$<span class="hljs-keyword">set</span>: {<span class="hljs-string">"nested"</span>: {<span class="hljs-string">"key"</span>: <span class="hljs-number">1</span>}}, $inc: {<span class="hljs-string">"nested.key"</span>: <span class="hljs-number">3</span>},
$mul: {<span class="hljs-string">"nested.key"</span>: <span class="hljs-number">2</span>}, $rename: {<span class="hljs-string">"nested.key"</span>: <span class="hljs-string">"accounts"</span>},
$unset: {<span class="hljs-string">"name"</span>: <span class="hljs-string">""</span>}}, {returnUpdatedDocs: <span class="hljs-literal">true</span>})
.then(<span class="hljs-function">(<span class="hljs-params">docs</span>) =></span> {
<span class="hljs-built_in">console</span>.log(docs[<span class="hljs-number">0</span>]); <span class="hljs-comment">// {_id: "...", nested: { accounts: 8 }}</span>
});
<span class="hljs-comment">// example of exactObjectFind</span>
<span class="hljs-comment">// exactObjectFind. you must send in object formatting.</span>
Users.update({
name: <span class="hljs-string">"t"</span>,
nested: {
key: <span class="hljs-number">2</span>
},
}, {
$<span class="hljs-keyword">set</span>: {<span class="hljs-string">"nested"</span>: {<span class="hljs-string">"key"</span>: <span class="hljs-number">1</span>}},
}, {
returnUpdatedDocs: <span class="hljs-literal">true</span>,
upsert: <span class="hljs-literal">true</span>,
exactObjectFind: <span class="hljs-literal">true</span>,
})
.then(<span class="hljs-function">(<span class="hljs-params">docs</span>) =></span> {
<span class="hljs-built_in">console</span>.log(docs[<span class="hljs-number">0</span>]); <span class="hljs-comment">// {_id: "...", name: "t", nested: {key: 1}}</span>
});
<span class="hljs-comment">// with another object</span>
<span class="hljs-keyword">const</span> incomingObj = externalAPI.request.data[<span class="hljs-number">0</span>];
Users.update(incomingObj, {$<span class="hljs-keyword">set</span>: {synced: <span class="hljs-literal">true</span>}}, {
upsert: <span class="hljs-literal">true</span>,
exactObjectFind: <span class="hljs-literal">true</span>
})
.then(resolve)
.catch(reject);
</code></pre>
<p>The <code>exactObjectFind</code> param is great for pulling down a repo that and updating lots of data. If you pull down data and need to compare it to an already stored object and rewrite that object if the incoming data has changed. This is the perfect solution. Upsert if not found and can send an entire object.</p>
<h2 id="remove">Remove</h2>
<p>Uses the find method to retrieve _ids and removes multiple always, as well as removing indexed items from the Mapped indices for all indexed items on a object. </p>
<pre><code class="lang-typescript">Users.remove({<span class="hljs-string">"nested.accounts"</span>: <span class="hljs-number">8</span>})
.then(<span class="hljs-function">(<span class="hljs-params">num</span>) =></span> {
<span class="hljs-built_in">console</span>.log(num); <span class="hljs-comment">// 1</span>
<span class="hljs-keyword">return</span> Users.find({<span class="hljs-string">"nested.accounts"</span>: <span class="hljs-number">8</span>});
})
.then(<span class="hljs-function">(<span class="hljs-params">docs</span>) =></span> {
<span class="hljs-built_in">console</span>.log(docs.length); <span class="hljs-comment">// 0</span>
});
<span class="hljs-comment">// If you would like to remove an object that exactly</span>
<span class="hljs-comment">// matches all parameters. If lets say you remove _id then </span>
<span class="hljs-comment">// you can use compressObj. Useful when you do not want to </span>
<span class="hljs-comment">// remove many.</span>
<span class="hljs-keyword">const</span> doc = {<span class="hljs-comment">/* contents */</span>};
<span class="hljs-keyword">const</span> target = {};
compressObj(doc, target);
Users.remove(target)
.then(resolve)
.catch(reject);
</code></pre>
<h2 id="utilities">Utilities</h2>
<p>There are many methods used internally for TeDB that are tested against many other methods to be very quick and easy to use. Some were build as promises and other as regular functions. The reason for each is dependant on how it is used within TeDB. However these methods have such great use we decided to export them and have them available to use. To keep the dependency list to only one, which is also written by one of the active contributors, we had to write many of our own helper methods instead of importing a larger library with many unused methods. Making this package a standalone database.</p>
<ul>
<li>TeDB Utilities<ul>
<li>range - create range of utf8 characters given two utf8 characters, or numbers descending/ascending</li>
<li>isEmpty - Return true if {}, [], "", null, undefined</li>
<li>getDate - Used to retrieve the Date from a _id of Datastore document if you would rather not used the Datastore method available.</li>
<li>rmObjDups - remove duplicate objects from an array. Only works for comparable <code>===</code> values</li>
<li>getPath - get the value given dot notated string path <code>"path.in.object"</code></li>
<li>Base64: class - encode and decode base 64 encoding with <code>==</code> at the end. used to make _ids</li>
<li>compareArray - Compare two arrays of equal length, returns 0 if equal, -1 if first is less and 1 if greater. Comparison only works for types <strong>string, number, Date</strong></li>
<li>NEW compressObj: - Convert object notation into dot object notation.</li>
<li>NEW expandObj: - Convert dot string notated object into expanded object.</li>
<li>NEW flatten: - Compress arrays of arrays into one array.</li>
<li>NEW saveArrDups: - Save duplicated items in array of arrays.</li>
<li>NEW getDups: - Compare two arrays and get only the duplicate items in new array.</li>
<li>NEW rmArrDups: - Remove duplicate items in array.</li>
</ul>
</li>
</ul>
<p>range</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> numbers: <span class="hljs-built_in">number</span>[] = range(<span class="hljs-number">-5</span>, <span class="hljs-number">5</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">number</span>[]; <span class="hljs-comment">// have to specify - bc multiple possibilities</span>
<span class="hljs-keyword">const</span> strs: <span class="hljs-built_in">string</span>[] = range(<span class="hljs-string">"a"</span>, <span class="hljs-string">"b"</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>[]; <span class="hljs-comment">// utf8 range</span>
</code></pre>
<p>isEmpty</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">console</span>.log(isEmpty([]) && isEmpty({}) && isEmpty(<span class="hljs-string">""</span>) && isEmpty(<span class="hljs-literal">null</span>) && isEmpty(<span class="hljs-literal">undefined</span>)); <span class="hljs-comment">// true</span>
</code></pre>
<p>getDate - shown above</p>
<p>rmObjDups</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> list = <span class="hljs-built_in">any</span>[] = [
{a: <span class="hljs-string">"a"</span>}, {a: <span class="hljs-string">"a"</span>}, {a: <span class="hljs-string">"b"</span>}, {a: <span class="hljs-string">"c"</span>}, {a: <span class="hljs-string">"c"</span>}, {a: <span class="hljs-string">"b"</span>}
];
<span class="hljs-keyword">const</span> newList = rmObjDups(list, <span class="hljs-string">"a"</span>);
<span class="hljs-built_in">console</span>.log(newList); <span class="hljs-comment">// [{a: "a"}, {a: "b"}, {a: "c"}]</span>
</code></pre>
<p>getPath</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> obj = {nested: {value: {is: {here: <span class="hljs-number">3</span>}}}};
<span class="hljs-built_in">console</span>.log(getPath(<span class="hljs-string">"nested.value.is.here"</span>)); <span class="hljs-comment">// 3</span>
</code></pre>
<p>Base64 - recommend reading the source</p>
<p>compressObj</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> doc: <span class="hljs-built_in">any</span> = { example: {obj: [<span class="hljs-number">1</span>,<span class="hljs-number">2</span>], is: <span class="hljs-string">"d"</span>}, great: <span class="hljs-number">9</span>};
<span class="hljs-keyword">const</span> target: <span class="hljs-built_in">any</span> = {};
compressObj(doc, target);
<span class="hljs-built_in">console</span>.log(target);
<span class="hljs-comment">// output</span>
<span class="hljs-comment">/*{
"example.obj.0": 1,
"example.obj.1": 2,
"example.is": "d",
"great": 9,
}*/</span>
</code></pre>
<p>expandObj</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> doc = {
<span class="hljs-string">"nested.reg.obj"</span>: <span class="hljs-number">5</span>,
<span class="hljs-string">"nested.dot.0"</span>: <span class="hljs-number">3</span>,
<span class="hljs-string">"nested.dot.1"</span>: <span class="hljs-number">4</span>,
<span class="hljs-string">"is"</span>: <span class="hljs-string">"nested"</span>,
<span class="hljs-string">"very.nested.obj.is.nested.far.in.obj"</span>: <span class="hljs-string">"hello"</span>;
}
<span class="hljs-keyword">const</span> expanded = expandObj(doc);
<span class="hljs-built_in">console</span>.log(expanded);
<span class="hljs-comment">// output</span>
<span class="hljs-comment">/*{
nested: {
reg: {
obj: 5,
},
dot: [3, 4],
},
is: "nested",
very: {nested: {obj: {is: {nested: {far: {in: {
obj: "hello",
}}}}}}}
}*/</span>
</code></pre>
<p>flatten</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> hArray = [[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>], <span class="hljs-number">3</span>, [[[[<span class="hljs-number">4</span>]],[<span class="hljs-number">5</span>]]],[<span class="hljs-number">6</span>,[[[<span class="hljs-number">7</span>]]]]];
<span class="hljs-built_in">console</span>.log(flatten(hArray)); <span class="hljs-comment">// [1,2,3,4,5,6,7];</span>
</code></pre>
<p>saveArrDups</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> dArray = [[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>],[<span class="hljs-number">1</span>],[<span class="hljs-number">23</span>,<span class="hljs-number">4</span>,<span class="hljs-number">1</span>,<span class="hljs-number">2</span>]];
saveArrDups(dArray)
.then(<span class="hljs-function">(<span class="hljs-params">res</span>) =></span> {
<span class="hljs-built_in">console</span>.log(res); <span class="hljs-comment">// [1, 1, 1];</span>
});
</code></pre>
<p>getDups</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> da = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>];
<span class="hljs-keyword">const</span> db = [<span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>];
<span class="hljs-built_in">console</span>.log(getDups(da, db)); <span class="hljs-comment">// [2, 3];</span>
</code></pre>
<p>rmArrDups</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> arrayD = [<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>];
<span class="hljs-built_in">console</span>.log(rmArrDups(arrayD)); <span class="hljs-comment">// [1, 2, 3];</span>
</code></pre>
<h2 id="license">License</h2>
<p>See <a href="LICENSE">License</a></p>
</div>
</div>
<div class="col-4 col-menu menu-sticky-wrap menu-highlight">
<nav class="tsd-navigation primary">
<ul>
<li class="globals ">
<a href="globals.html"><em>Globals</em></a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_cursor_.html">"cursor"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_datastore_.html">"datastore"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_index_.html">"index"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_indices_.html">"indices"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_types_irange_.html">"types/IRange"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_types_iindexoptions_.html">"types/<wbr>Iindex<wbr>Options"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_types_iupdateoptions_.html">"types/<wbr>Iupdate<wbr>Options"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_types_index_.html">"types/index"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_types_storagedriver_.html">"types/storage<wbr>Driver"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_updateoperators_.html">"update<wbr>Operators"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_utils_base64_.html">"utils/base64"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_utils_comparearray_.html">"utils/compare<wbr>Array"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_utils_compressobj_.html">"utils/compress<wbr>Obj"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_utils_expandobj_.html">"utils/expand<wbr>Obj"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_utils_flatten_.html">"utils/flatten"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_utils_getdups_.html">"utils/get<wbr>Dups"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_utils_id_hasher_.html">"utils/id_<wbr>hasher"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_utils_index_.html">"utils/index"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_utils_misc_.html">"utils/misc"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_utils_range_.html">"utils/range"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_utils_rmarrdups_.html">"utils/rm<wbr>Arr<wbr>Dups"</a>
</li>
<li class=" tsd-kind-external-module">
<a href="modules/_utils_savearrdups_.html">"utils/save<wbr>Arr<wbr>Dups"</a>
</li>
</ul>
</nav>
<nav class="tsd-navigation secondary menu-sticky">
<ul class="before-current">
</ul>
</nav>
</div>
</div>
</div>
<footer class="with-border-bottom">
<div class="container">
<h2>Legend</h2>
<div class="tsd-legend-group">
<ul class="tsd-legend">
<li class="tsd-kind-module"><span class="tsd-kind-icon">Module</span></li>
<li class="tsd-kind-object-literal"><span class="tsd-kind-icon">Object literal</span></li>
<li class="tsd-kind-variable"><span class="tsd-kind-icon">Variable</span></li>
<li class="tsd-kind-function"><span class="tsd-kind-icon">Function</span></li>
<li class="tsd-kind-function tsd-has-type-parameter"><span class="tsd-kind-icon">Function with type parameter</span></li>
<li class="tsd-kind-index-signature"><span class="tsd-kind-icon">Index signature</span></li>
<li class="tsd-kind-type-alias"><span class="tsd-kind-icon">Type alias</span></li>
</ul>
<ul class="tsd-legend">
<li class="tsd-kind-enum"><span class="tsd-kind-icon">Enumeration</span></li>
<li class="tsd-kind-enum-member"><span class="tsd-kind-icon">Enumeration member</span></li>
<li class="tsd-kind-property tsd-parent-kind-enum"><span class="tsd-kind-icon">Property</span></li>
<li class="tsd-kind-method tsd-parent-kind-enum"><span class="tsd-kind-icon">Method</span></li>
</ul>
<ul class="tsd-legend">
<li class="tsd-kind-interface"><span class="tsd-kind-icon">Interface</span></li>
<li class="tsd-kind-interface tsd-has-type-parameter"><span class="tsd-kind-icon">Interface with type parameter</span></li>
<li class="tsd-kind-constructor tsd-parent-kind-interface"><span class="tsd-kind-icon">Constructor</span></li>
<li class="tsd-kind-property tsd-parent-kind-interface"><span class="tsd-kind-icon">Property</span></li>
<li class="tsd-kind-method tsd-parent-kind-interface"><span class="tsd-kind-icon">Method</span></li>
<li class="tsd-kind-index-signature tsd-parent-kind-interface"><span class="tsd-kind-icon">Index signature</span></li>
</ul>
<ul class="tsd-legend">
<li class="tsd-kind-class"><span class="tsd-kind-icon">Class</span></li>
<li class="tsd-kind-class tsd-has-type-parameter"><span class="tsd-kind-icon">Class with type parameter</span></li>
<li class="tsd-kind-constructor tsd-parent-kind-class"><span class="tsd-kind-icon">Constructor</span></li>
<li class="tsd-kind-property tsd-parent-kind-class"><span class="tsd-kind-icon">Property</span></li>
<li class="tsd-kind-method tsd-parent-kind-class"><span class="tsd-kind-icon">Method</span></li>
<li class="tsd-kind-accessor tsd-parent-kind-class"><span class="tsd-kind-icon">Accessor</span></li>
<li class="tsd-kind-index-signature tsd-parent-kind-class"><span class="tsd-kind-icon">Index signature</span></li>
</ul>
<ul class="tsd-legend">
<li class="tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited constructor</span></li>
<li class="tsd-kind-property tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited property</span></li>
<li class="tsd-kind-method tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited method</span></li>
<li class="tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited accessor</span></li>
</ul>
<ul class="tsd-legend">
<li class="tsd-kind-property tsd-parent-kind-class tsd-is-protected"><span class="tsd-kind-icon">Protected property</span></li>
<li class="tsd-kind-method tsd-parent-kind-class tsd-is-protected"><span class="tsd-kind-icon">Protected method</span></li>
<li class="tsd-kind-accessor tsd-parent-kind-class tsd-is-protected"><span class="tsd-kind-icon">Protected accessor</span></li>
</ul>
<ul class="tsd-legend">
<li class="tsd-kind-property tsd-parent-kind-class tsd-is-private"><span class="tsd-kind-icon">Private property</span></li>
<li class="tsd-kind-method tsd-parent-kind-class tsd-is-private"><span class="tsd-kind-icon">Private method</span></li>
<li class="tsd-kind-accessor tsd-parent-kind-class tsd-is-private"><span class="tsd-kind-icon">Private accessor</span></li>
</ul>
<ul class="tsd-legend">
<li class="tsd-kind-property tsd-parent-kind-class tsd-is-static"><span class="tsd-kind-icon">Static property</span></li>
<li class="tsd-kind-call-signature tsd-parent-kind-class tsd-is-static"><span class="tsd-kind-icon">Static method</span></li>
</ul>
</div>
</div>
</footer>
<div class="container tsd-generator">
<p>Generated using <a href="http://typedoc.org/" target="_blank">TypeDoc</a></p>
</div>
<div class="overlay"></div>
<script src="assets/js/main.js"></script>
<script>if (location.protocol == 'file:') document.write('<script src="assets/js/search.js"><' + '/script>');</script>
</body>
</html>