@hunter_outlaw

Как правильно скопировать большой объем данных в свою MongoDb?

Здравствуйте!
Есть Api который отдает населенные пункты в json формате. Их там много, более 15000, отдает постранично, по 150 штук.
Необходимо скопировать базу себе в MongoDb предварительно внеся правки в объекты.
Время от времени нужно обновлять свою базу. Соответственно копировать себе нужно с соблюдением условия: если населенный пункт уже есть в базе - обновить, если нет - создать.

Вопросы:
1. Как правильно реализовать копирование, чтобы не положить сервер БД от количества запросов?
2. Можно ли сделать массовое копирование (добавление/обновление) опираясь на ID населенного пункта?
3. Как правильно делать паузы между запросами, чтобы не убивать сервер?

Сейчас сделал так:
const updateCities = async function(page) {
            const limit = 150;
            const require = {
                limit: limit,
                Page: page
            }
            return api.address.getSettlements(require).then((json) => {
                // Перебираем все города на странице
                    if(json.data.length !== 0) {
                        for (var obj of json.data) {
                            saveCity(obj);
                        }

                        let log = `Page: ${page}, Results: ${json.data.length} \n`;
                        console.log(log);

                        return log;
                    }else{
                        return;
                    }

            }).catch((errors) => {
                if (Array.isArray(errors)) {
                    errors.forEach((error) => console.log(`[${ error.code || '-' }] ${ error.en || error.uk || error.ru || error.message }`));
                }

                res.type('json');
                res.send(errors);
                res.status(200).send();
            });
        }

        // Вызываем функцию постраничной выборки городов 
        // Создавая между ними ${delay} секунд задержки
            let delay = 2000;
            let page = 0;
            let returnMsg = '';
            let timerId = setTimeout(async function request() {
                let updateCitiesReturn = await updateCities(page);
                returnMsg += updateCitiesReturn;
                page++;

                if(updateCitiesReturn){
                    timerId = setTimeout(request, delay);
                }else{
                    res.type('json');
                    res.send(returnMsg);
                    res.status(200).send();
                }
            }, delay);

        // Сохраняем город
           async function saveCity(obj) {
               // Добавляем/обновляем город в БД
                   const cities = await loadCities();
                   await cities.updateOne({ _id: obj.Ref }, {$set: obj}, {upsert: true});
           }


В результате в какой-то момент база перестает отвечать из-за большого количества вставок/обновлений, даже не смотря на паузы между запросами. Касательно пауз, это отдельный вопрос)
Подозреваю, что не самое грамотное решение, поэтому обращаюсь за консультацией
  • Вопрос задан
  • 81 просмотр
Решения вопроса 2
hzzzzl
@hzzzzl
for (var obj of json.data) {
       saveCity(obj);
}

...

await cities.updateOne({ _id: obj.Ref }, {$set: obj}, {upsert: true});


есть же updateMany, зачем для каждой записи вызывать updateOne
https://docs.mongodb.com/manual/reference/method/d...

UPD
наверно лучше подойдет bulkWrite, куда вкинешь массив на 150 элементов за раз
https://docs.mongodb.com/manual/reference/method/d...
Ответ написан
Комментировать
@hunter_outlaw Автор вопроса
Спасибо, bulkWrite - то, что доктор прописал!
Получилось так:
....................
						let insertDocument = [];
                        for (var obj of json.data) {
                            let cityType;
                            if(obj.SettlementTypeDescription === 'місто') {
                                cityType = 1;
                                cityMark = 'м.';
                                cityMarkRu = 'г.';
                            }else if(obj.SettlementTypeDescription === 'селище міського типу') {
                                cityType = 2;
                                cityMark = 'смт.';
                                cityMarkRu = 'пгт.';
                            }else if(obj.SettlementTypeDescription === 'село') {
                                cityType = 3;
                                cityMark = 'с.';
                                cityMarkRu = 'с.';
                            }else if(obj.SettlementTypeDescription === 'селище') {
                                cityType = 3;
                                cityMark = 'сел.';
                                cityMarkRu = 'пос.';
                            }

                            let newCityObj = {
                                _id: obj.Ref,
                                redionId: obj.Region,
                                areaId: obj.Area,
                                lat: obj.Latitude,
                                lng: obj.Longitude,
                                index: obj.Index1,
                                fullTitle: {
                                    ua: `${cityMark} ${obj.Description}, ${obj.RegionsDescription}, ${obj.AreaDescription}`,
                                    ru: `${cityMarkRu} ${obj.DescriptionRu}, ${obj.RegionsDescriptionRu}, ${obj.AreaDescriptionRu}`
                                },
                                title: {
                                    ua: obj.Description,
                                    ru: obj.DescriptionRu
                                },
                                regionTitle: {
                                    ua: obj.RegionsDescription,
                                    ru: obj.RegionsDescriptionRu
                                },
                                areaTitle: {
                                    ua: obj.AreaDescription,
                                    ru: obj.AreaDescriptionRu
                                },
                                typeTitle: {
                                    ua: obj.SettlementTypeDescription,
                                    ru: obj.SettlementTypeDescriptionRu
                                },
                                type:cityType
                            }

                            insertDocument.push({ 
                                "updateOne": {
                                    "filter": { "_id": obj.Ref }, 
                                    "update": { $set : newCityObj },
                                    "upsert": true
                                }
                            });
                        }
                        
                        // Добавляем/обновляем город в БД
                            saveCity(insertDocument)
							
						...........


async function saveCity(obj) {
							const cities = await loadCities();
							await cities.bulkWrite(obj)
						}
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
dimonchik2013
@dimonchik2013
non progredi est regredi
сервер, похоже, никакой

впиши каждый запрос в txt файл, потом в один поток сымпорти
хз что там за настройки, что он ложится от 15к каких-то
Ответ написан
Комментировать
@emp1re
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы