A TypeScript Embedded Database. A structure sane embedded database with pluggable storage and clean concise documentation.


If you would to support the development of this project. This project is ongoing and this also will be donations for support of storage drivers written by tedb-org as well.

  • Bitcoin Address: 1Hn3HZUgkwaLcm5go18FJco6dH92nbxLn2
  • Ethereum Address: 0x13E6e0D78901ce97d4115EA05DF1D32d363F8E51
  • Litecoin Address: LVLMPsN6W1i8DddJa8MiQWPMU246QmZpq4


TeDB uses an AVL balanced binary tree binary-type-tree 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.

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.

Writing a storage driver for TeDB

There is a very simple example of a NodeJS storage driver in the /spec/example directory that is used for the testing of the datastore. You can also see an example of what a data store preferably should look from your storage driver for nodejs in the /spec/fixtures/db 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. source.

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.

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.

Storage drivers

  • tedb-electron-storage – the example storage driver in this package

Creating a Datastore

Each database will consist of however many datastores you would 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”.

For the storage driver it should have the methods found on the storage driver interface found here. Now that you have the datastore created you can insert and query on those inserted items. Each item inserted has an automatic _id generated for them. This _id also saves the created on Date. The _ids are not indexed automatically but can be if you decide to.


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. _ids are created each time you insert an object into TeDB. The values of the key value store are always arrays.

{ “myUserNameValue”: [“_idofobject”]} if the index is not unique then the value is still an array except for each matching key the new ids are added. { “actualAge#”: [“_id1”, “_id2”, “_id3”]}.

  • Index Options
    • fieldName – The path as a string “” to be indexed on the object
    • unique – Set value to have a unique restriction or not
    • checkKeyEquality – You can pass your own equality check method: Default
    • compareKeys – You can pass your own method to compare keys: Default

return Users.ensureIndex;

If you ever need to use some of the other index methods such as insertIndex, removeIndex, or saveIndex the getIndices will be needed. DS stands for Datastore and SD for Storage Driver.

  • getIndices: DS – returns a promise containing the index map of this datastore
  • saveIndex: DS – saves a JSON representation of the index using the storage driver
  • removeIndex: DS – 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.
  • insertIndex: DS – Insert a JSON representation of an index into this datastore's index Map.
  • removeIndex: SD – Should delete the location of the stored index, dependent on the SD method.
  • fetchIndex: SD – Should return the parsed index from storage
  • storeIndex: SD – Should save the index



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.

Find/Count and Get Date from _id

Find uses a cursor class to work through a query object. Find always returns an array.

  • Cursor Options
    • sort – Sort by field {fieldName: -1 } or {fieldName: 1 }
    • skip – Skip a certain number of returned items
    • limit – Set a limit to max number of items returned
    • exec – execute the search using the cursor options, will search for all docs query before applying the sort, skip, or limit methods on them.

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 keys 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.

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.

Find now supports a special sort field $created_at for sorting your documents by created at time. Each _id holdsthe time of creation down to the millisecond. We would advise against creating your own created_at time or any $fields in your documents. We might, in the future, add extra functionality to more $ fields.

  • Find query options
    • $or – search an object query of one or multiple
    • $and – search an object with and results or multiple
    • $gt, $lt, $gte, $lte, $ne – can combine any assortment.

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.

TeDB also stores the time inserted.


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.

  • Update Options
    • multi – return many documents: Default false
    • upsert – insert the document if not found: Default false, creates _id on insert
    • returnUpdatedDocs – returns all the docs after being updated and stored.
    • exactObjectFind – when finding objects search the exact object itself. Cannot use find queries such as $gt, $lt. Best used with updating an object completely if anything changes.
  • Update Operators
    • $set – write, overwrite a value to the document/s that are returned. Warning Cannot create an object from undefined.
    • $mul – multiply the value with the given query value
    • $inc – increment a positive or negative number to the value of the document
    • $unset – delete the value from the object
    • $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.

Users.updateincomingObj, , 

The exactObjectFind 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.


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.


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.

  • TeDB Utilities
    • range – create range of utf8 characters given two utf8 characters, or numbers descending/ascending
    • isEmpty – Return true if {}, [], “”, null, undefined
    • getDate – Used to retrieve the Date from a _id of Datastore document if you would rather not used the Datastore method available.
    • rmObjDups – remove duplicate objects from an array. Only works for comparable === values
    • getPath – get the value given dot notated string path “”
    • Base64: class – encode and decode base 64 encoding with == at the end. used to make _ids
    • 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 string, number, Date
    • NEW compressObj: – Convert object notation into dot object notation.
    • NEW expandObj: – Convert dot string notated object into expanded object.
    • NEW flatten: – Compress arrays of arrays into one array.
    • NEW saveArrDups: – Save duplicated items in array of arrays.
    • NEW getDups: – Compare two arrays and get only the duplicate items in new array.
    • NEW rmArrDups: – Remove duplicate items in array.



console.logisEmpty && isEmpty && isEmpty”” && isEmptynull && isEmptyundefined; 

getDate – shown above




Base64 – recommend reading the source







console.loggetDupsda, db; 




See License


Как дома оцифровать 8-миллиметровую плёнку с семейным киноархивом


Наверняка у многих пылятся на полке катушки киноленты с семейным архивом, который снят на плёнку 8 мм.

Рано или поздно у владельцев этих сокровищ возникает желание и дальше сохранять семейные реликвии. Но не на хрупкой портящейся киноленте, а на современных цифровых носителях.

И для этого нужно сделать оцифровку киноплёнки с наименьшей потерей качества кадров. Что предпринять в этой ситуации?

Оцифровать самостоятельно в домашних условиях кинопленку можно двумя методами.

Осуществить такое желание в наше время особого труда не составит, достаточно обратиться в фирму, которая занимается оцифровкой подобной киноплёнки, таких фирм достаточно много. Всё было бы хорошо, если б не цена, которая на самом деле «кусается».

Есть ещё один вариант — оцифровать самому, если имеется цифровая видеокамера. Но одной камеры недостаточно, как минимум, нужен ещё раритетный кинопроектор (например, Русь), который придётся немного переделать.

Съёмка непосредственно с экрана

Самый простой и малозатратный способ — это прямая пересъёмка проецируемого кинопроектором изображения непосредственно с экрана. Съёмка осуществляется в следующих вариантах:

  • съёмка с абсолютным затемнением с расстояния в пару метров от экрана;
  • проекция кинокадров с незначительного расстояния на белый бумажный лист, используемый в качестве экрана;
  • съёмка камерой с передачей видео непосредственно в компьютер, а можно перегнать в компьютер позже с кассеты видеокамеры.

Способ не потребует особых ухищрений и доработок, при этом позже не надо почти ничего делать — получается практически полноценная копия изображения.

Практическая сторона

Для того чтобы осуществить на практике эти методы, понадобится 8-миллиметровый проектор советских времён, к примеру, «Луч» или «Русь». Скорей всего, такой проектор у владельцев архивов сохранился.

Дорабатывать его для такого способа пересъёмки не потребуется. Разве что надо будет заменить пассики, если они не хранились отдельно, смазанные силиконовой смазкой. Скорей всего, они потрескались за долгие годы и пришли в негодность. Ну и, конечно, смазать и почистить сам аппарат.

В качестве экрана можно применить специальный экран или же белую простыню. Можно и просто побеленную стену. Но более высокое качество получается при использовании листа белой бумаги. Единственный нюанс — бумага не должна быть глянцевой.

Камера при съёмке находится на очень близком расстоянии от экрана, что позволяет добиться хорошего качества резкости. Изображение выходит более ярким, и не требуется абсолютное затемнение. Но при этом могут возникнуть искажения изображения, так как получается большой угол оптических осей.

Многие пытались решить эту проблему, используя молочного цвета стекло, как экран. Оптические оси камеры и проектора совпадали, а съёмка осуществлялась на просвет. Но метод себя не оправдал, так как ровного освещения достичь очень непросто — центральная часть экрана освещается намного сильнее.

Передача изображения на компьютер

Для того чтобы оцифровать киноплёнку, подходят любые типовые видеокамеры стандартного образца. Рассматривать всерьёз видеоресурсы цифровых фотоаппаратов, планшетов и других гаджетов не стоит.

Лучше всего, если это будет цифровая видеокамера, так как при этом изображение уже получится в нужном цифровом формате. Но вполне сгодятся и аналоговые видеокамеры, правда, потом надо будет оцифровывать аналоговое изображение при помощи плат оцифровки телетюнера или специальной платы для видеомонтажа.

Снимать на цифровую камеру гораздо удобнее, так как снимается изображение сразу на носитель камеры и потом сбрасывается на компьютер. При этом в стоящем рядом компьютере нет необходимости.

При съёмке аналоговой камерой в любом случае возникнут помехи во время записи и дальнейшего считывания с неё. Поэтому лучше всего изображение передавать сразу на компьютер.

Минусы метода

ВАЖНО. Независимо от вышеперечисленных вариантов, такой «пиратский» способ переснять старую киноплёнку не даёт необходимого качества полученного изображения. 

Обычно человеческий глаз воспринимает перерыв между сменами кадров как мерцание. Чтобы это мерцание было незаметным, пионеры кинематографии придумали обтюратор.

При проецировании кадров на экран он своими тремя лопастями перекрывает пучок света, идущий от проекционной лампы. И именно в одно из таких перекрытий света происходит та самая смена кадра.

Человеческие глаза при этом видят ровное изображение на своём экране.

Но светочувствительность видеокамеры во много раз выше, чем у человеческого глаза, поэтому в итоге на отснятых кадрах будут видны то нормальные кадры, то чёрные, то перекрытые частично обтюратором.

К тому же автоэкспозиция самой камеры зачастую не может нормально настроиться на смену чёрному обычному кадру, поэтому возникают колебания яркости.

Дополнительная обработка такого изображения ни к чему не приведёт.

Поэтому энтузиасты методом проб и ошибок, разработали другие способы оцифровки киноплёнки 8 мм в домашних условиях, которые дают очень неплохие результаты.

Пересъёмка по кадрам

Почти идеальный результат получается, если снимать по одному кинокадру в момент их остановки. Один видеокадр на один кинокадр. Здесь возникают технические трудности:

  • захватить кадр именно в момент остановки;
  • перегрев плёнки при длительной остановке либо при медленном движении;

Для того чтобы захваченный кадр, переданный на компьютер, строго соответствовал моменту полной остановки кинокадра, необходима доработка проектора. Чтобы синхронизировать момент захвата, на проекторе устанавливают микродатчик (выключатель). Его приводит в действие выступ, установленный на главный вал проектора. Таким образом, подаётся сигнал захвата одного кадра на компьютер.

цель доработки — отрегулировать фазу срабатывания датчика в момент полной неподвижности кадра. Для этого необходимо удалить с проектора обтюратор. Настройку будет выполнить гораздо легче, так как время для захвата кадра увеличится чуть ли не в 3 раза.

Качественный захват кадра таким путём можно осуществить только на максимально маленькой скорости — до 10 к/с и менее. Поэтому для того, чтобы не допустить перегревания плёнки, энтузиасты используют определённые приёмы. Как выполнить эти пункты доработки в домашних условиях, будет сказано ниже.

Как установить датчик

Простейший датчик представляет собой микровыключатель, который можно приобрести отдельно или взять из старой компьютерной мыши. Сигнал с такого датчика будет поступать на компьютер, который при помощи соответствующей программы даст команду на захват одного кадра. Далее вал проектора делает ещё один оборот, кадр меняется, и датчик снова выдаёт сигнал на захват.

Компьютерные программы для захвата используются стандартные, найти их не составит большого труда. Они позволяют выполнять захват кадра при клике мышью по определённой кнопке программы. Для этого на нужные контакты мыши выводят сигнал от замыкания датчика.

Удаление обтюратора

Как выше было сказано, обтюратор нужно удалить для того, чтобы он своими лопастями не перекрывал свет, идущий на кадровое окно от лампы проектора.

Если проектор планируется использовать и дальше, то процедура разборки и последующей сборки проектора окажется довольно сложной. Гораздо проще будет удалить обтюратор «варварским» способом — просто срезать лопасти обтюратора ножницами по металлу.

Как не допустить перегрева плёнки

В стандартном проекторе учтена вероятность перегревания плёнки при замедленных режимах проекции и длительных остановках. Поэтому для защиты плёнки в нём имеется ещё один тепловой фильтр, который перекрывает свет лампы при падении скорости ниже 5 к/с.

Примерно на такой же скорости ведётся съёмка в настоящих условиях, и тепловой фильтр будет сильно мешать. Поэтому его или блокируют в открытом виде, или просто снимают. Сразу же встаёт вопрос, как защитить плёнку. Для этого могут использоваться три варианта действий, которые можно применить:

  • наблюдать за скоростью и сразу же отключать лампу при незапланированной остановке.
  • ставить дополнительный вентилятор;
  • менять обычную лампу на энергосберегающую, к примеру, светодиодную.

Если же в проекторе останется стандартная лампа, то к задней крышке проектора можно установить вентилятор от старого блока питания компьютера. Такой вентилятор питается током в 12 В, и напряжение можно получить от питания лампы, которое выпрямляется диодным мостиком.

Подобной вентиляции вполне хватит для охлаждения внезапно остановившейся плёнки. Во всяком случае времени для ручного отключения лампы будет достаточно, так как плёнка не пожелтеет в течение пяти секунд.

Выполнив основные доработки, можно приступать к оцифровке киноплёнки 8 мм с обработкой отснятого или захваченного в компьютер видеофайла фильтром GetDups (ГетДапс). В результате получится качественная цифровая копия старого кинофильма.

Пересъёмка «объектив в объектив»

Такой метод пересъёмки потребует пару хитростей в доработке проектора. В первую очередь, замены стандартного объектива на короткофокусный объектив от любой телескопической системы. Качества изображения будет добиться гораздо проще, если фокусное расстояние такого объектива будет близким или даже превышающим фокусное расстояние видеокамеры.

У кинолюбителей довольно популярна оцифровка киноплёнки 8 мм таким способом, так как доработки выполнить немного проще.

Здесь так же, как и при покадровой пересъёмке, потребуется замена лампы, но меняется она по другим соображениям.

Так как пересъёмка методом «объектив в объектив» ведётся почти с обычной скоростью, перегрев плёнки не страшен. Менее мощная лампа применяется для уменьшения светового потока на фотоприёмник видеокамеры.

При оцифровке чёрно-белой плёнки будет нелишним применить светофильтр, чтобы избежать виньетирования изображения. Он ставится между лампой и плёнкой. Лучше всего использовать интерференционный фильтр, так как у него довольно узкая пропускная полоса. Но можно использовать и обычный красный светофильтр.

Сама конструкция проектор-видеокамера устанавливается на жёсткое основание, но с таким расчётом, чтобы была возможность двигать камеру вверх-вниз и влево вправо. Это нужно для совмещения оптических осей двух объективов. Скорость проекции кадров подбирается такая, чтобы не было мигания, а запись изображения лучше сразу передавать на компьютер.

Следует упомянуть о некоторых технических моментах, которые могут возникнуть в процессе работы:

  • проектор снижает скорость ниже 5 к/с только в прогретом состоянии, в холодном же он этого делать «не хочет».
  • если на холодный проектор сразу установить маленькую скорость, то он может не начать работу. Лучше работу начинать на средних показателях, и понемногу их уменьшать.
  • повышение скорости проектора на слух довольно сложно определить. Но можно записать звук на необходимой скорости и включать эту запись для сравнения.

Собственно это основные методы оцифровки дома. Существует ещё множество ухищрений умельцев, о которых можно прочитать на форумах, поэкспериментировать, но рассказ о них — это отдельная тема. Если у вас есть свой метод оцифровки, поделитесь с нами в комментарии.


Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: