Git Stash

Я прямо влюбился в команду stash от git, хотя к самому git отношусь без … фанатизма.

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

Сохранение изменений

git stash save "description of stash"

… создать stash с человекопонятным описанием этого stash - чтобы можно было через день, глядя на него, догадаться вообще, что это такое и зачем оно делалось.

git stash -u save "description of stash"

… создать stash с изменениями, которые еще unstaged. Иначе они просто не попадут в снимок stash.

git stash branch newAwesomeBranch

… создание новой ветки из stash@{0}. Важный момент - чтобы изменения попали с новую ветку, они должны сначала быть помещены в stash@{0}.

git stash branch newAwesomeBranch stash@{1}

… поместить изменения из конктерного stash@{1} в новую ветку newAwesomeBranch.

git stash -p

… выборочное сохранение измененых файлов. Запускается пошаговый мастер, который будет последовательно спрашивать - помещать измененый файл в stash или нет.

Показ сохраненных изменений

git stash show

… показать, какие файлы изменены. Краткая справка, которая просто показывает, где были изменения и в каких файлах.

git stash show stash@{1}

… показать краткие изменения в конкретном stash.

git stash show -p stash@{1}

… показать изменения в файле. Можно увидеть в файле, что было добавлено или удалено.

git stash list

… показать список всех снимков stash. Причем, снимок с номером stash@{0} - это самый последний по времени снимок stash. Дальше - понарастающей - чем больше номер, тем раньше по времени он был сделан.

Удаление сохраненных изменений

git stash drop stash@{1}

… удалить определенный снимок stash@{1}.

git stash drop

… удалить последний снимок stash@{0}.

git stash clear

… удалить все изменения stash.

Применение сохраненных изменений

git stash apply

… применить последний по времени снимок stash.

git stash apply stash@{2}

… применить конкретный снимок stash.

git stash pop

… сокрещение от двух команд - apply и drop - применяет и автоматически удаляет после применения последний снимок stash - stash@{0}.

git stash pop stash@{2}

… сокрещение от двух команд - apply и drop - применяет и автоматически удаляет после применения конкретный снимок stash - stash@{2}.

Шаблон раннего возврата (return early pattern) в JavaScript - это простой способ уменьшить число else-операторов в теле функции до нуля. Есть много причин, чтобы предпочесть этот шаблон использованию else-операторов.

  • Уменьшение общего количества кода на странице
  • Уменьшение длины строк кода упрощением логической сложности
  • Улучшение удобочитаемости кода

Суть шаблона раннего возврата (return early pattern) заключается в том, чтобы заменить необходимость дополнительных условий в функциях JavaScript, используя ключевое слово return в теле оператора if.

Создадим функцию, которая ведет себя по-разному при определенных условиях (примечание: это тривиальный и надуманный пример, просто чтобы получить представление о сути вопроса):

function willItBlend (someObject) {
var ItWillBlend;

if (someObject.blendable === 'It will blend') {
itWillBlend = true;
} else {
itWillBlend = false;
}

return itWillBlend;
}

Хотя данная функция кажется читаемой, добавим в нее еще одно условие для проверки того, что функция вызывается для работы с объектом вместо undefined:

function willItBlend(someObject) {
var itWillBlend;

if (typeof someObject === 'object') {
if (someObject.blendable === 'It will blend') {
itWillBlend = true;
} else {
itWillBlend = false;
}
} else {
itWillBlend = false;
}

return itWillBlend;
}

Эта функция понятной и ее имя является описательным, однако она представляется все-же излишне сложной. Можем ли мы использовать шаблон раннего возврата (return early pattern) для повышения удобочитаемости и уменьшения количества else-выражений?

Попробуем:

function willItBlend(someObject) {
if (typeof someObject !== 'object') {
return false;
}

if (someObject.blendable !== 'It will blend') {
return false;
}

return true;
}

Используя шаблон раннего возврата (return early pattern), мы смогли удалить все ненужные else-инструкции и сделать функцию намного яснее и более краткой.

Бонус: одно условное выражение

Мы можем дополнительно переписать функцию для использования только одного оператора if.

Проверим:

function willItBlend(someObject) {
if (
typeof someObject !== 'object' ||
someObject.blendable !== 'It will blend'
) {
return false;
}

return true;
}

Метод call

Метод call и apply достаточно древние - они оба из стандарта ES3. Суть создания и работы методов - заставить некоторую произвольную функцию работать на каком-то объекте. Точнее - использовать контекст этого объекта.

Чтобы было понятнее, начнем с примера. Есть функция, которая работает таким образом:

function getName() {
  const name = this.name
  console.log(name)
}

Что будет, если вызвать эту функцию таким образом?

getName()

Сложный вопрос, так как мы видим, что в теле функции используется ключевое слово this. Это - ссылка на текущий объект и на свойство name этого объекта. Что это за объект? Неизвестно. Все будет зависеть от того, где будет вызвана функция getName() на исполнение. Допустим, если вызвать функцию в консоли браузера, то парсер обратиться к глобальному объекту window и попробует найти у него свойство name. В итоге мы получим undefined, так как вряд ли у объекта window есть свойство name.

При помощи метода call можно “привязать” функцию getName() к любому объекту. Другими словами - привязать контекст функции getName() к контексту объекта. Как?

Допустим, у нас есть объект:

const user1 = {
  name: 'Ivan',
  position: 'frontent developer',
  salary: 1200
}

Мы сделаем так:

const result1 = getName.call(user1)

Что будет происходить здесь? В этом случае ключевое слово this (в теле функции getName) будет указывать на объект user1, у которого есть свойство name. Как результат - в константе result1 будет находиться значение Ivan.

Если создадим еще один объект:

const user2 = {
  name: 'Joshua',
  position: 'ui designer',
  salary: 2200
}

И на нем вызовем функцию getName():

const result2 = getName.call(user2)

Что будет? В этом случае функция getName будет ссылаться уже на объект user2! И в константе result2 уже будет значение свойства name объекта user2 - Joshua.

call - более сложный вариант

Рассмотрим более сложный случай - когда функция принимает аргумент(ы). Допустим, такая функция,

function promote(position, salary) {
  this.salary = salary
  this.position = position
  return this.position + ' earns ' + this.salary + ' dollars'
}

И есть два объекта:

const junior = {
  name: 'Fritz',
  position: 'junior developer',
  salary: 1000
}
const middle = {
  name: 'Max',
  position: 'middle developer',
  salary: 2000
}
const senior = {
  name: 'Manu',
  position: 'senior developer',
  salary: 3000
}

Вызовем функцию promote() на каждом из объектов:

const result1 = promote.call(junior, 'super junior developer', 1200)
const result2 = promote.call(middle, 'super middle developer', 2200)
const result3 = promote.call(senior, 'super senior developer', 3200)

Что здесь произойдет? При каждом вызове функции promote() у нее будет разный контекст выполнения - объект junior, middle или senior. И обращаться функция promote() будет каждый раз к свойствам разных объектов - junior, middle или senior. Соответственно, результат тоже будет разным:

super junior developer earns 1200 dollars
super middle developer earns 2200 dollars
super senior developer earns 3200 dollars

Метод apply

Метод apply очень похож на метод call, за одним исключением. Аргументы метод apply принимает в виде массива, а не в виде списка, как метод call.

Проиллюстрируем пример - переделаем вызов функции promote() при помощи метода apply:

const resultA = promote.apply(junior, [ 'super junior developer', 1200 ])
const resultB = promote.apply(middle, [ 'super middle developer', 2200 ])
const resultC = promote.apply(senior, [ 'super senior developer', 3200 ])

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

Метод bind

Этот метод похож на предыдущие два - call и apply. Однако, у него есть два отличия - этот метод появился в стандарте ES5; и второе отличие - этот метод позволяет выполнить отложенный вызов функции.

То есть - метод call или apply вызываются на исполнение сразу, и результат их работы мы получаем сразу. С методом bind немного иначе:

const resultAA = promote.bind(junior)
const resultBB = promote.bind(middle)
const resultCC = promote.bind(senior)

Что мы сдесь сделали? Мы вызвали функции promote() и передали ей контекст выполнения; результат - экземпляр функции promote() с уже встроенным контекстом выполнения; экземпляр помещен в константу resultAA, resultBB или resultCC. Другими словами - это готовые функции с контекстом.

Осталось вызвать любую из них и передать ей аргументы, которые она ожидает:

const resultAAA = resultAA('super junior developer', 1200)
const resultBBB = resultBB('super middle developer', 2200)
const resultCCC = resultCC('super senior developer', 3200)

Получим результат:

super junior developer earns 1200 dollars
super middle developer earns 2200 dollars
super senior developer earns 3200 dollars

Видим - мы получили отложенный вызов каждой из функций.

MongoDB

Приступили к самому основному - операциям создания, чтения, изменения и удаления документов в MongoDB.

Аббревиатура для этих четырех операций - CRUD ( Create, Read, Update, Delete ).

В этом обзоре будет рассмотрен процесс создания документа - Create.

Два основных метода для создания нового документа в коллекции - метод insert и метод save.

Метод insert()

Команда создания нового документа в коллекции выглядит так:

db.COLLECTION_NAME.insert(document)

COLLECTION_NAME - это имя коллекции, в которой будет создаваться новый документ. document - это JavaScript-объект.

Создам новый документ в коллекции customers базы данных users. Для этого перейду в эту базу данных:

> use users
switched to db users

Создам коллецию customers в базе данных users:

> db.createCollection('customers')
{ "ok" : 1 }

Создам в коллекции customers новый документ. Можно использовать как одинарные, так и двойные кавычки - дело вкуса:

> db.customers.insert( { name: 'Leanne Graham', username: 'Bret', email: 'sincere@april.biz' } )
WriteResult({ "nInserted" : 1 })

MongoDB выдает отчет о выполнении команды в строке:

...
WriteResult({ "nInserted" : 1 })

Видно, что операция WriteResult успешно выполнилась - nInserted в значении true.

Как хорошо видно, создаваемый документ - это объект. Если нужно создать сразу несколько документов, то методу insert передается массив этих объектов:

> db.customers.insert( [ { name: 'Ervin Howell', username: 'Antonette', email: 'shanna@melissa.tv' }, { name: 'Clementine Bauch', username: 'Samantha', email: 'nathan@yesenia.net' } ] )
BulkWriteResult({
	"writeErrors" : [ ],
	"writeConcernErrors" : [ ],
	"nInserted" : 2,
	"nUpserted" : 0,
	"nMatched" : 0,
	"nModified" : 0,
	"nRemoved" : 0,
	"upserted" : [ ]
})

BulkWriteResult выдает подробную информацию о выполненных операциях. Видно, что была выполнена только операция создания документа - “nInserted” : 2.

Просмотр списка документов

Вывести список созданных документов в коллекции customers можно при помощи метода .find():

> db.customers.find()
{ "_id" : ObjectId("59200cdc2bd83e7289a5cae4"), "name" : "Leanne Graham", "username" : "Bret", "email" : "sincere@april.biz" }
{ "_id" : ObjectId("59200e3b2bd83e7289a5cae5"), "name" : "Ervin Howell", "username" : "Antonette", "email" : "shanna@melissa.tv" }
{ "_id" : ObjectId("59200e3b2bd83e7289a5cae6"), "name" : "Clementine Bauch", "username" : "Samantha", "email" : "nathan@yesenia.net" }
>

Видно, что у каждого созданного мною документа есть ключ _id со значением ObjectId(). Этого ключа я не указывал при создании документа.

Все правильно - этот ключ и его значение MongoDB генерирует автоматически и присваивает каждому создаваемому документу. Таким образом MongoDB делает все документы уникальными - нет ни одного документа с одинаковым _id.

Можно сделать вывод метода .find() более читабельным, если подключить к нему по цепочке еще один метод - .pretty():

> db.customers.find().pretty()
{
	"_id" : ObjectId("59200cdc2bd83e7289a5cae4"),
	"name" : "Leanne Graham",
	"username" : "Bret",
	"email" : "sincere@april.biz"
}
{
	"_id" : ObjectId("59200e3b2bd83e7289a5cae5"),
	"name" : "Ervin Howell",
	"username" : "Antonette",
	"email" : "shanna@melissa.tv"
}
{
	"_id" : ObjectId("59200e3b2bd83e7289a5cae6"),
	"name" : "Clementine Bauch",
	"username" : "Samantha",
	"email" : "nathan@yesenia.net"
}
>

Метод save()

С помощью метода save() также можно создавать новый документ в коллекции. Создам еще один документ:

> db.customers.save( { name: 'Patricia Lebsack', username: 'Karianne', email: 'julianne.conner@kory.org' } )
WriteResult({ "nInserted" : 1 })

Сообщение от MongoDB говорит мне, что операция была выполнена успешно. Посмотрю на результат:

> db.customers.find()
{ "_id" : ObjectId("59200cdc2bd83e7289a5cae4"), "name" : "Leanne Graham", "username" : "Bret", "email" : "sincere@april.biz" }
{ "_id" : ObjectId("59200e3b2bd83e7289a5cae5"), "name" : "Ervin Howell", "username" : "Antonette", "email" : "shanna@melissa.tv" }
{ "_id" : ObjectId("59200e3b2bd83e7289a5cae6"), "name" : "Clementine Bauch", "username" : "Samantha", "email" : "nathan@yesenia.net" }
{ "_id" : ObjectId("592013152bd83e7289a5cae7"), "name" : "Patricia Lebsack", "username" : "Karianne", "email" : "julianne.conner@kory.org" }
>

Отличие метода save() от метода insert() заключается в том, что если при создании документа будет передан ключ _id уже существующего документа, то существующий документ будет перезаписан новым.

Вот у меня создан документ:

> db.customers.save( { name: 'Chelsey Dietrich', username: 'kamren', email: 'Lucio_Hettinger@annie.ca' } )
WriteResult({ "nInserted" : 1 })

И он успешно добавлен в коллекцию customers с уникальным ключом “_id” : ObjectId(“5920166b986c86064996f59e”):

> db.customers.find()
{ "_id" : ObjectId("59200cdc2bd83e7289a5cae4"), "name" : "Leanne Graham", "username" : "Bret", "email" : "sincere@april.biz" }
{ "_id" : ObjectId("59200e3b2bd83e7289a5cae5"), "name" : "Ervin Howell", "username" : "Antonette", "email" : "shanna@melissa.tv" }
{ "_id" : ObjectId("59200e3b2bd83e7289a5cae6"), "name" : "Clementine Bauch", "username" : "Samantha", "email" : "nathan@yesenia.net" }
{ "_id" : ObjectId("5920166b986c86064996f59e"), "name" : "Chelsey Dietrich", "username" : "kamren", "email" : "Lucio_Hettinger@annie.ca" }
> 

Теперь я создаю новый документ, но передаю в него существующую пару ключ-значение “_id” : ObjectId(“5920166b986c86064996f59e”):

> db.customers.save( { "_id" : ObjectId("5920166b986c86064996f59e"), name: 'Chelsey Dietrich', username: 'chelsey', email: 'c.dietrich@gmail.com' } )
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

Смотрю результат:

> db.customers.find()
{ "_id" : ObjectId("59200cdc2bd83e7289a5cae4"), "name" : "Leanne Graham", "username" : "Bret", "email" : "sincere@april.biz" }
{ "_id" : ObjectId("59200e3b2bd83e7289a5cae5"), "name" : "Ervin Howell", "username" : "Antonette", "email" : "shanna@melissa.tv" }
{ "_id" : ObjectId("59200e3b2bd83e7289a5cae6"), "name" : "Clementine Bauch", "username" : "Samantha", "email" : "nathan@yesenia.net" }
{ "_id" : ObjectId("5920166b986c86064996f59e"), "name" : "Chelsey Dietrich", "username" : "chelsey", "email" : "c.dietrich@gmail.com" }
>

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

На этом все.


MongoDB

Что такое document

Понятие документа - основа MongoDB. Недаром говорится, что MongoDB - документо-ориентированная система управления базами данных.

Document входит в состав collection и наполняет ее содержимым. Document - это обычный JSON-объект.

Если есть навык создания и работы с JSON-объектами, то уже можно создавать документы в MongoDB.

Простой пример документа в базе данных MongoDB:

{
  "_id" : ObjectId("591f49970f7b726a5beb58af"),
  "name" : "Anna"
}

Стоит обратить внимание на ключ “_id” - этот ключ и значение ключа MongoDB автоматически генерирует для уникальной идентификации каждого документа в базе данных.

Чуть более сложный пример документа в MongoDB:

{
	"_id" : ObjectId("591f49970f7b726a5beb58af"),
	"name" : "Anna",
	"surname" : "Tudor",
	"music" : [
		"country",
		"blues",
		"chill-out"
	],
	"age" : 18,
	"virgin" : true
}

В данном случае документ состоит из нескольких типов данных - Number, Array, String, Boolean.

Два документа в коллекции canada базы данных users:

{
	"_id" : ObjectId("591f49970f7b726a5beb58af"),
	"name" : "Anna",
	"surname" : "Tudor",
	"music" : [
		"country",
		"blues",
		"chill-out"
	],
	"age" : 18,
	"virgin" : true
}
{
	"_id" : ObjectId("591f4eaf02ed4d6e1d81bc97"),
	"name" : "Leanne Graham",
	"username" : "Bret",
	"email" : "Sincere@april.biz",
	"address" : {
		"street" : "Kulas Light",
		"suite" : "Apt. 556",
		"city" : "Gwenborough",
		"zipcode" : "92998-3874",
		"geo" : {
			"lat" : "-37.3159",
			"lng" : "81.1496"
		}
	},
	"phone" : "1-770-736-8031 x56442",
	"website" : "hildegard.org"
}

Таких документов в коллекции canada может быть сколько угодно.

Вот в принципе и все, что нужно знать о документах в MongoDB.

На этом все.