Страницы

Поиск по вопросам

Показаны сообщения с ярлыком mongodb. Показать все сообщения
Показаны сообщения с ярлыком mongodb. Показать все сообщения

понедельник, 13 апреля 2020 г.

Подтверждение записи данных в mongoDB

#python #mongodb #pymongo

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


Ответы

Ответ 1



Для этой цели в MongoDB специально введено понятние Write Concern. Выдержка из документации: write concern Specifies whether a write operation has succeeded. Write concern allows your application to detect insertion errors or unavailable mongod instances. For replica sets, you can configure write concern to confirm replication to a specified number of members. See Write Concern. Дословно: Указывает, успешно ли выполнилась операция записи. "Write concern" позволяет вашим приложениям выявлять ошибки вставки или недоступности mongod. Для replica-set вы можете задать write concern, чтобы подтверждать репликацию в заданное число реплик. Существует определенный набор значений для этого параметра: Unacknowledged Acknowledged (by default) Journaled Replica Acknowledged По умолчанию драйвером используется Acknowledged уровень - mongod в этом случае будет сообщать клиенту о результатах записи. Т.е. клиент может отловить сетевые ошибки , получить сообщение duplicate key или другую ошибку. (Всё расписано в документации). Значение write concern'а в драйвере можно поменять в классе MongoClient.

суббота, 4 апреля 2020 г.

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

#mongodb #nosql

                    
Есть коллекция с документами вида:

{
    "_id" : ObjectId("56e17f2db292c9151a8b459b"),
    "title" : "test title",
    "category" : "test category",
    "pubDate" : "1457599100",
    "code" : "ZZZ"
},
{
    "_id" : ObjectId("56e17f2db292c9151a8b459b"),
    "title" : "test 2 title",
    "category" : "test 2 category",
    "pubDate" : "1457599200",
    "code" : "ZZZ"
}


Как сделать группировку, чтобы получить на выходе что-то типа этого:

{
  "ZZZ": {
    "items": {
      0:{
         "_id" : ObjectId("56e17f2db292c9151a8b459b"),
         "title" : "test title",
         "category" : "test category",
         "pubDate" : "1457599100"
      },
      1:{
         "_id" : ObjectId("56e17f2db292c9151a8b459b"),
         "title" : "test 2 title",
         "category" : "test 2 category",
         "pubDate" : "1457599100"
      }
    }
  }
}

    


Ответы

Ответ 1



Используйте Aggregation Framework и оператор $group: db.test.aggregate([ { $group: { _id: "$code", "items": { $push: { "_id": "$_id", "title": "$title", "category": "$category", "pubDate": "$pubDate" } } } } ]) Результат запроса: [ { "_id" : "ZZZ", "items" : [ { "_id" : ObjectId("56e17f2db292c9151a8b459b"), "title" : "test title", "category" : "test category", "pubDate" : "1457599100" }, { "_id" : ObjectId("56e17f2db292c9151a8a459b"), "title" : "test 2 title", "category" : "test 2 category", "pubDate" : "1457599200" } ] } ] Полученный результат слегка отличается от запрошенного, но, в целом, можно настроить его, поработав с $project.

воскресенье, 29 марта 2020 г.

Преобразовать данные из MongoDB

#java #spring #mongodb #spring_boot


Есть класс Person, в нем есть поле name. Я записываю эти данные в Mongo, но на выходе,
хочу получать не записанные по 1-у классы, а все поля name из них, но в List.
Вот код 

@RestController
public class Post_Get {
    @Autowired
    private PersonRepository personRepository;
    private List persons = new ArrayList<>();

    @PostMapping("api/names")
    public void post (@RequestParam("username") String name) {
        Person person = new Person(name);
        personRepository.save(person);
    }

    @GetMapping("api/names")
    public List get () {
        return personRepository.findAll();
    }
}

    


Ответы

Ответ 1



@GetMapping("api/names") public List getNames() { return personRepository.findAll() .stream() .map(Person::getName) .filter(Objects::nonNull) .collect(Collectors.toList()); } Или без лишней конвертаций public interface PersonRepository extends Repository { Stream findByNameNotNull(); } @GetMapping("api/names") public List getNames() { return personRepository.findByNameNotNull() .map(Person::getName) .collect(Collectors.toList()); }

воскресенье, 9 февраля 2020 г.

MongoDB, поиск по регулярному выражению

#регулярные_выражения #nodejs #mongodb


Добрый день!
В документе есть поле size (строка) вида 134-140, 140-146 и тп. Делаю запрос

var s = "134";
var reg = new RegExp (`[${s}]`, "i");
collection.find({size:{$regex:reg}}).toArray(function(err, result){
                console.log(result);
});


По идее, должно вернуть все документы, где в поле size встречается цифры 134 (точнее
строка). Но возвращает абсолютно все документы. Что я делаю не так?

П.С. после многочисленных тестов я  определил, что возвращаются не все документы,
а только те, где встречается хотя бы один символ из регулярного выражения.  В данном
случае  134. Так, будто квадратных скобок нет.
Версия MongoDB-сервера 3.0, модуль версии 3.0
    


Ответы

Ответ 1



var reg = /134/; collection.find({ size: { $regex: reg, $options: 'i' } }) UPD: var s = "134"; var reg = ".*" + s ".*"; collection.find({ size: { $regex: reg, $options: 'i' } })

Ответ 2



Так как не ответили выше, в чём ошибка, дополню. У вас в регулярном выражении строка вида [123], то есть ищется любой из указаных в скобках символов. Вы это сами заметили: после многочисленных тестов я определил, что возвращаются не все документы, а только те, где встречается хотя бы один символ из регулярного выражения. В данном случае 134 А что вы ожидали от квадратных скобок? Так, будто квадратных скобок нет. Почитать об этом можно, например, вот тут или тут.

пятница, 24 января 2020 г.

MongoDB - тормоз вставки после 5000000 записей

#java #база_данных #mongodb #nosql #mongodb_query


Всем привет. В общем проблема такая: Проект на JAVA и есть NoSQL DB - MongoDB, необходимо
работать примерно с 1000000000 записей. Вставка, в пустую таблицу, 5000000 записей,
происходит за 13-15 мин, но после вставки 5000000 дальнейший процесс вставки начинает
тормозить и чуть ли не в геометрической прогрессии и ОЗУ начинает пожирать немерено.
Приоритетной задачей этой БД является поиск (скорость поиска на 10000000 - удовлетворяющая)  

Вопрос: 


Почему так происходит?  
Как это исправить?


Возможные варианты решения:


Каждые 5000000 записей - создавать новую таблицу?
Оптимизация индексов? (у меня поиск по id)
Оптимизация конфига MongoDB?
Оптимизация системы?
Замена БД?


Заранее благодарен за ответ!
    


Ответы

Ответ 1



У меня был похожий случай когда я работал с SQLite. Приходилось перейти на MySQL. Но для миллиарда записей по моему вам надо будет перейти уже на BigTable. Например, на Hadoop, HBase или Cassandra. Насчет Cassandra если честно не уверен, потому что Facebook сам перешел от Cassandra на HBase хотя сами разработали ее. bigtableбаза-данных

среда, 22 января 2020 г.

Падает Mongo при $lookup c pipeline

#ubuntu #mongodb


При попытке сделать присоединение коллекции orders к items:

db.items.aggregate(
[{
  $lookup:
         {
           from: "orders",
           let: {id: "$_id"},
           pipeline: [
              { $match:
                 { $expr:
                    {$and:
                       [
                         {$eq: [ "$item_id",  "$$id" ]},
                       ]
                    }
                 }
              }
           ],
           as: "orders"
         }
}] , {"allowDiskUse": true}
)


Происходит падение базы, в логах вот это

[conn4] Invariant failure Hit a MONGO_UNREACHABLE! src/mongo/db/query/collation/collation_spec.cpp 90
2019-09-16T13:31:12.093+0000 F  -        [conn4] 

***aborting after invariant() failure


2019-09-16T13:31:12.198+0000 F  -        [conn4] Got signal: 6 (Aborted).
 0x56443e4c0741 0x56443e4bff3e 0x56443e4bffd6 0x7f2f78491890 0x7f2f780cce97 0x7f2f780ce801
0x56443c944a52 0x56443e3bfa74 0x56443d3cce9d 0x56443d3cdb35 0x56443d3ced38 0x56443d3d0fea
0x56443d3d1538 0x56443cbbb37f 0x56443cbb9684 0x56443cbba1fb 0x56443ddc058e 0x56443ddc0fb7
0x56443de0848d 0x56443d3a1065 0x56443d3a0ed6 0x56443d3a1618 0x56443d3e9180 0x56443d3e990d
0x56443d0f178d 0x56443d0f608f 0x56443d0e97a5 0x56443ce13859 0x56443ce14f13 0x56443ce15dce
0x56443ce166a0 0x56443ce046cc 0x56443ce1028c 0x56443ce0bc0f 0x56443ce0ee8c 0x56443dbefd52
0x56443ce0962d 0x56443ce0c8c3 0x56443ce0acf7 0x56443ce0bb6b 0x56443ce0ee8c 0x56443dbf01bb
0x56443e252874 0x7f2f784866db 0x7f2f781af88f
----- BEGIN BACKTRACE -----
{"backtrace":[{"b":"555B94758000","o":"287C741","s":"_ZN5mongo15printStackTraceERSo"},{"b":"555B94758000","o":"287BF3E"},{"b":"555B94758000","o":"287BFD6"},{"b":"7F84F5092000","o":"12890"},{"b":"7F84F4CA1000","o":"3EE97","s":"gsignal"},{"b":"7F84F4CA1000","o":"40801","s":"abort"},{"b":"555B94758000","o":"D00A52","s":"_ZN5mongo22invariantFailedWithMsgEPKcRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES1_j"},{"b":"555B94758000","o":"277BA74","s":"_ZNK5mongo13CollationSpec6toBSONEv"},{"b":"555B94758000","o":"1788E9D"},{"b":"555B94758000","o":"1789B35","s":"_ZN5mongo9PipelineD15prepareExecutorEPNS_16OperationContextEPNS_10CollectionERKNS_15NamespaceStringEPNS_8PipelineERKN5boost13intrusive_ptrINS_17ExpressionContextEEEbRKNSB_INS_18DocumentSourceSortEEESt10unique_ptrINS_36GroupFromFirstDocumentTransformationESt14default_deleteISL_EERKNS_11DepsTrackerERKNS_7BSONObjEPKNS_18AggregationRequestERKyPSS_S10_"},{"b":"555B94758000","o":"178AD38","s":"_ZN5mongo9PipelineD30buildInnerQueryExecutorGenericEPNS_10CollectionERKNS_15NamespaceStringEPKNS_18AggregationRequestEPNS_8PipelineE"},{"b":"555B94758000","o":"178CFEA","s":"_ZN5mongo9PipelineD23buildInnerQueryExecutorEPNS_10CollectionERKNS_15NamespaceStringEPKNS_18AggregationRequestEPNS_8PipelineE"},{"b":"555B94758000","o":"178D538","s":"_ZN5mongo9PipelineD42buildAndAttachInnerQueryExecutorToPipelineEPNS_10CollectionERKNS_15NamespaceStringEPKNS_18AggregationRequestEPNS_8PipelineE"},{"b":"555B94758000","o":"F7737F","s":"_ZN5mongo24MongoInterfaceStandalone40attachCursorSourceToPipelineForLocalReadERKN5boost13intrusive_ptrINS_17ExpressionContextEEEPNS_8PipelineE"},{"b":"555B94758000","o":"F75684","s":"_ZN5mongo24MongoInterfaceStandalone28attachCursorSourceToPipelineERKN5boost13intrusive_ptrINS_17ExpressionContextEEEPNS_8PipelineE"},{"b":"555B94758000","o":"F761FB","s":"_ZN5mongo24MongoInterfaceStandalone12makePipelineERKSt6vectorINS_7BSONObjESaIS2_EERKN5boost13intrusive_ptrINS_17ExpressionContextEEENS_21MongoProcessInterface19MakePipelineOptionsE"},{"b":"555B94758000","o":"217C58E","s":"_ZN5mongo20DocumentSourceLookUp13buildPipelineERKNS_8DocumentE"},{"b":"555B94758000","o":"217CFB7","s":"_ZN5mongo20DocumentSourceLookUp7getNextEv"},{"b":"555B94758000","o":"21C448D","s":"_ZN5mongo8Pipeline7getNextEv"},{"b":"555B94758000","o":"175D065","s":"_ZN5mongo18PipelineProxyStage11getNextBsonEv"},{"b":"555B94758000","o":"175CED6","s":"_ZN5mongo18PipelineProxyStage6doWorkEPm"},{"b":"555B94758000","o":"175D618","s":"_ZN5mongo9PlanStage4workEPm"},{"b":"555B94758000","o":"17A5180","s":"_ZN5mongo16PlanExecutorImpl12_getNextImplEPNS_11SnapshottedINS_7BSONObjEEEPNS_8RecordIdE"},{"b":"555B94758000","o":"17A590D","s":"_ZN5mongo16PlanExecutorImpl7getNextEPNS_7BSONObjEPNS_8RecordIdE"},{"b":"555B94758000","o":"14AD78D"},{"b":"555B94758000","o":"14B208F","s":"_ZN5mongo12runAggregateEPNS_16OperationContextERKNS_15NamespaceStringERKNS_18AggregationRequestERKNS_7BSONObjERKSt6vectorINS_9PrivilegeESaISC_EEPNS_3rpc21ReplyBuilderInterfaceE"},{"b":"555B94758000","o":"14A57A5"},{"b":"555B94758000","o":"11CF859"},{"b":"555B94758000","o":"11D0F13"},{"b":"555B94758000","o":"11D1DCE"},{"b":"555B94758000","o":"11D26A0","s":"_ZN5mongo23ServiceEntryPointCommon13handleRequestEPNS_16OperationContextERKNS_7MessageERKNS0_5HooksE"},{"b":"555B94758000","o":"11C06CC","s":"_ZN5mongo23ServiceEntryPointMongod13handleRequestEPNS_16OperationContextERKNS_7MessageE"},{"b":"555B94758000","o":"11CC28C","s":"_ZN5mongo19ServiceStateMachine15_processMessageENS0_11ThreadGuardE"},{"b":"555B94758000","o":"11C7C0F","s":"_ZN5mongo19ServiceStateMachine15_runNextInGuardENS0_11ThreadGuardE"},{"b":"555B94758000","o":"11CAE8C"},{"b":"555B94758000","o":"1FABD52","s":"_ZN5mongo9transport26ServiceExecutorSynchronous8scheduleESt8functionIFvvEENS0_15ServiceExecutor13ScheduleFlagsENS0_23ServiceExecutorTaskNameE"},{"b":"555B94758000","o":"11C562D","s":"_ZN5mongo19ServiceStateMachine22_scheduleNextWithGuardENS0_11ThreadGuardENS_9transport15ServiceExecutor13ScheduleFlagsENS2_23ServiceExecutorTaskNameENS0_9OwnershipE"},{"b":"555B94758000","o":"11C88C3","s":"_ZN5mongo19ServiceStateMachine15_sourceCallbackENS_6StatusE"},{"b":"555B94758000","o":"11C6CF7","s":"_ZN5mongo19ServiceStateMachine14_sourceMessageENS0_11ThreadGuardE"},{"b":"555B94758000","o":"11C7B6B","s":"_ZN5mongo19ServiceStateMachine15_runNextInGuardENS0_11ThreadGuardE"},{"b":"555B94758000","o":"11CAE8C"},{"b":"555B94758000","o":"1FAC1BB"},{"b":"555B94758000","o":"260E874"},{"b":"7F84F5092000","o":"76DB"},{"b":"7F84F4CA1000","o":"12188F","s":"clone"}],"processInfo":{
"mongodbVersion" : "4.2.0", "gitVersion" : "a4b751dcf51dd249c5865812b390cfd1c0129c30",
"compiledModules" : [ "enterprise" ], "uname" : { "sysname" : "Linux", "release" :
"4.15.0-62-generic", "version" : "#69-Ubuntu SMP Wed Sep 4 20:55:53 UTC 2019", "machine"
: "x86_64" }, "somap" : [ { "b" : "555B94758000", "elfType" : 3, "buildId" : "4EE35FDC2FB7C1DC9AE0FA065B98E2666BC5E79C"
}, { "b" : "7FFFBC3FD000", "path" : "linux-vdso.so.1", "elfType" : 3, "buildId" : "17ABBA294C8661C069F5408AC1D74F121AD71734"
}, { "b" : "7F84F7C96000", "path" : "/usr/lib/x86_64-linux-gnu/libnetsnmpmibs.so.30",
"elfType" : 3, "buildId" : "0B3EDB4E9A96E0B0AB1E2301298314F0509D6E69" }, { "b" : "7F84F7A87000",
"path" : "/usr/lib/x86_64-linux-gnu/libsensors.so.4", "elfType" : 3, "buildId" : "B21B5590FA3766E5B4D33C6619E7FC3C6EFB343B"
}, { "b" : "7F84F787A000", "path" : "/lib/x86_64-linux-gnu/libpci.so.3", "elfType"
: 3, "buildId" : "2E20D61921C8C482DDCC973352AA823D54A6C75E" }, { "b" : "7F84F7676000",
"path" : "/lib/x86_64-linux-gnu/libdl.so.2", "elfType" : 3, "buildId" : "25AD56E902E23B490A9CCDB08A9744D89CB95BCC"
}, { "b" : "7F84F740D000", "path" : "/usr/lib/x86_64-linux-gnu/libnetsnmpagent.so.30",
"elfType" : 3, "buildId" : "496196D52AF5622F412B8B4A38075E7509426548" }, { "b" : "7F84F7203000",
"path" : "/lib/x86_64-linux-gnu/libwrap.so.0", "elfType" : 3, "buildId" : "93E8EE4A51AEB0FCCDE2C0CEF42F3F43637482E7"
}, { "b" : "7F84F6F27000", "path" : "/usr/lib/x86_64-linux-gnu/libnetsnmp.so.30", "elfType"
: 3, "buildId" : "11C46888E6D931CC8C4733FA2E9DDF66AA685C33" }, { "b" : "7F84F6A5C000",
"path" : "/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1", "elfType" : 3, "buildId" : "CB6876717C83B0CC01C3C919B9B6E86D8554F546"
}, { "b" : "7F84F680A000", "path" : "/usr/lib/x86_64-linux-gnu/libldap_r-2.4.so.2",
"elfType" : 3, "buildId" : "70EEF126558D1559A0A4E334FB68E4E9AABE90CB" }, { "b" : "7F84F65FC000",
"path" : "/usr/lib/x86_64-linux-gnu/liblber-2.4.so.2", "elfType" : 3, "buildId" : "C14042EC7BD22B9A07D2C16563FE3C2606F52AB7"
}, { "b" : "7F84F63E1000", "path" : "/usr/lib/x86_64-linux-gnu/libsasl2.so.2", "elfType"
: 3, "buildId" : "ABB7E3F40302E6509DAD1F91DFB1F04B6A5FD072" }, { "b" : "7F84F6196000",
"path" : "/usr/lib/x86_64-linux-gnu/libgssapi_krb5.so.2", "elfType" : 3, "buildId"
: "00F419F64B0E70D8C5EEF7050369AA40B2A6E090" }, { "b" : "7F84F5F17000", "path" : "/usr/lib/x86_64-linux-gnu/libcurl.so.4",
"elfType" : 3, "buildId" : "1C6BC2C0699CE0F7E848CA0B267E0CF07553F6AB" }, { "b" : "7F84F5B79000",
"path" : "/lib/x86_64-linux-gnu/libm.so.6", "elfType" : 3, "buildId" : "A33761AB8FB485311B3C85BF4253099D7CABE653"
}, { "b" : "7F84F595E000", "path" : "/lib/x86_64-linux-gnu/libresolv.so.2", "elfType"
: 3, "buildId" : "390E9CC4C215314B6D8ADE6D6E28F8518418039C" }, { "b" : "7F84F56D1000",
"path" : "/usr/lib/x86_64-linux-gnu/libssl.so.1.1", "elfType" : 3, "buildId" : "439A262CC0127BA401707DEC7A28884D617550E0"
}, { "b" : "7F84F54C9000", "path" : "/lib/x86_64-linux-gnu/librt.so.1", "elfType" :
3, "buildId" : "9826FBDF57ED7D6965131074CB3C08B1009C1CD8" }, { "b" : "7F84F52B1000",
"path" : "/lib/x86_64-linux-gnu/libgcc_s.so.1", "elfType" : 3, "buildId" : "41BDC55C07D5E5B1D8AB38E2C19B1F535855E084"
}, { "b" : "7F84F5092000", "path" : "/lib/x86_64-linux-gnu/libpthread.so.0", "elfType"
: 3, "buildId" : "28C6AADE70B2D40D1F0F3D0A1A0CAD1AB816448F" }, { "b" : "7F84F4CA1000",
"path" : "/lib/x86_64-linux-gnu/libc.so.6", "elfType" : 3, "buildId" : "B417C0BA7CC5CF06D1D1BED6652CEDB9253C60D0"
}, { "b" : "7F84F8111000", "path" : "/lib64/ld-linux-x86-64.so.2", "elfType" : 3, "buildId"
: "64DF1B961228382FE18684249ED800AB1DCEAAD4" }, { "b" : "7F84F4A84000", "path" : "/lib/x86_64-linux-gnu/libz.so.1",
"elfType" : 3, "buildId" : "EF3E006DFE3132A41D4D4DC0E407D6EA658E11C4" }, { "b" : "7F84F4866000",
"path" : "/lib/x86_64-linux-gnu/libudev.so.1", "elfType" : 3, "buildId" : "81D246A5D1C93AD88B13BB890B6A4D784FF9C421"
}, { "b" : "7F84F4469000", "path" : "/usr/lib/x86_64-linux-gnu/libperl.so.5.26", "elfType"
: 3, "buildId" : "CA3489D4F5936D6DD4FA45CC902CBDE6E90C4557" }, { "b" : "7F84F424F000",
"path" : "/lib/x86_64-linux-gnu/libnsl.so.1", "elfType" : 3, "buildId" : "B7FE43B6E487E0DD408E0F98008AAEA12EECC66C"
}, { "b" : "7F84F400E000", "path" : "/usr/lib/x86_64-linux-gnu/libgssapi.so.3", "elfType"
: 3, "buildId" : "A1A98DB481968073636BBAECB561A3EA8ED198AE" }, { "b" : "7F84F3CA9000",
"path" : "/usr/lib/x86_64-linux-gnu/libgnutls.so.30", "elfType" : 3, "buildId" : "E5AE5C31F804BE96532D0DB2091F19E472F2D4A0"
}, { "b" : "7F84F39D3000", "path" : "/usr/lib/x86_64-linux-gnu/libkrb5.so.3", "elfType"
: 3, "buildId" : "69FBCF425EE6DF03DE93B82FBC2FC33790E68A96" }, { "b" : "7F84F37A1000",
"path" : "/usr/lib/x86_64-linux-gnu/libk5crypto.so.3", "elfType" : 3, "buildId" : "F400D5D643A7F9696DF0E6148FA99BEE6C1BDDF7"
}, { "b" : "7F84F359D000", "path" : "/lib/x86_64-linux-gnu/libcom_err.so.2", "elfType"
: 3, "buildId" : "C0CB7E35A4566A443F99DFBC1A54D3A0677C8A10" }, { "b" : "7F84F3392000",
"path" : "/usr/lib/x86_64-linux-gnu/libkrb5support.so.0", "elfType" : 3, "buildId"
: "D78D71E8E016A534281B25B97CD7E5E9DB5FE00A" }, { "b" : "7F84F316D000", "path" : "/usr/lib/x86_64-linux-gnu/libnghttp2.so.14",
"elfType" : 3, "buildId" : "4F00E5207693FDC249DA42EC6472ACA6A7B929AE" }, { "b" : "7F84F2F50000",
"path" : "/usr/lib/x86_64-linux-gnu/libidn2.so.0", "elfType" : 3, "buildId" : "BA5BF9A5C44F48C647E9D8270A5421AE81CCAD61"
}, { "b" : "7F84F2D34000", "path" : "/usr/lib/x86_64-linux-gnu/librtmp.so.1", "elfType"
: 3, "buildId" : "69465D8AA6B19086ABF2455A703F9168BF82A69F" }, { "b" : "7F84F2B26000",
"path" : "/usr/lib/x86_64-linux-gnu/libpsl.so.5", "elfType" : 3, "buildId" : "CDAF1F1946846941F9D06414EC8C812D131A168E"
}, { "b" : "7F84F28EE000", "path" : "/lib/x86_64-linux-gnu/libcrypt.so.1", "elfType"
: 3, "buildId" : "810686AF0D5FD350A4FB1CC4B5AFF44A05C102CB" }, { "b" : "7F84F26E5000",
"path" : "/usr/lib/x86_64-linux-gnu/libheimntlm.so.0", "elfType" : 3, "buildId" : "C2376C5B831991591F1A67B976758185F86896D8"
}, { "b" : "7F84F2458000", "path" : "/usr/lib/x86_64-linux-gnu/libkrb5.so.26", "elfType"
: 3, "buildId" : "69BDEE5FA0FEEDF317308BE850F78761861D520A" }, { "b" : "7F84F21B6000",
"path" : "/usr/lib/x86_64-linux-gnu/libasn1.so.8", "elfType" : 3, "buildId" : "315D74995AAA32DE4D15BA25F335066988B1B230"
}, { "b" : "7F84F1F80000", "path" : "/usr/lib/x86_64-linux-gnu/libhcrypto.so.4", "elfType"
: 3, "buildId" : "6673972A1C24A89EBAFBAE696188A4CB26C6DDEB" }, { "b" : "7F84F1D6A000",
"path" : "/usr/lib/x86_64-linux-gnu/libroken.so.18", "elfType" : 3, "buildId" : "430827C33259C12248CF44B91A9A9821114376F5"
}, { "b" : "7F84F1A3B000", "path" : "/usr/lib/x86_64-linux-gnu/libp11-kit.so.0", "elfType"
: 3, "buildId" : "8DBD451EA5651283905E16FA7DFA9908688893A3" }, { "b" : "7F84F16BD000",
"path" : "/usr/lib/x86_64-linux-gnu/libunistring.so.2", "elfType" : 3, "buildId" :
"0E2784298E7D3F4D894FE130ACEFA77C3E624F72" }, { "b" : "7F84F14AA000", "path" : "/usr/lib/x86_64-linux-gnu/libtasn1.so.6",
"elfType" : 3, "buildId" : "6036B89A3BB671B32E01464C0C82BFA016186352" }, { "b" : "7F84F1274000",
"path" : "/usr/lib/x86_64-linux-gnu/libnettle.so.6", "elfType" : 3, "buildId" : "C20D4B3BA13FCDCC3BF6857689BA9FC70BE3F6A5"
}, { "b" : "7F84F1040000", "path" : "/usr/lib/x86_64-linux-gnu/libhogweed.so.4", "elfType"
: 3, "buildId" : "842BDF0B0EAAB82E19F1EABFC38769F4040FBE31" }, { "b" : "7F84F0DBF000",
"path" : "/usr/lib/x86_64-linux-gnu/libgmp.so.10", "elfType" : 3, "buildId" : "D40EA9B5EC5BC46799E4A412319617BD38BE9341"
}, { "b" : "7F84F0BBB000", "path" : "/lib/x86_64-linux-gnu/libkeyutils.so.1", "elfType"
: 3, "buildId" : "F463E107B099910463BC32E837C73D341A52C27B" }, { "b" : "7F84F0992000",
"path" : "/usr/lib/x86_64-linux-gnu/libwind.so.0", "elfType" : 3, "buildId" : "93A0931B1C2818F0EA224CE6FE5E31E84A9B55BB"
}, { "b" : "7F84F0783000", "path" : "/usr/lib/x86_64-linux-gnu/libheimbase.so.1", "elfType"
: 3, "buildId" : "669D4CCE42FA4382796EFFCF0C16F459F4382C4C" }, { "b" : "7F84F0539000",
"path" : "/usr/lib/x86_64-linux-gnu/libhx509.so.5", "elfType" : 3, "buildId" : "4B80C543356EE0AF9039EFE7C9EA1CC1F74C426A"
}, { "b" : "7F84F0230000", "path" : "/usr/lib/x86_64-linux-gnu/libsqlite3.so.0", "elfType"
: 3, "buildId" : "BCE351987CF42B3D258B09F0CAC867758D935086" }, { "b" : "7F84F0028000",
"path" : "/usr/lib/x86_64-linux-gnu/libffi.so.6", "elfType" : 3, "buildId" : "3555B5F599C9787DFDDBF9E8DF6F706B9044D985"
}, { "b" : "7F84EFE23000", "path" : "/usr/lib/x86_64-linux-gnu/sasl2/liblogin.so",
"elfType" : 3, "buildId" : "F74A279C265B0FEC0186260FC84749911A909A59" }, { "b" : "7F84EFC1C000",
"path" : "/usr/lib/x86_64-linux-gnu/sasl2/libsasldb.so", "elfType" : 3, "buildId" :
"9CEB11BBC12C2D2DAF0BA8BA0648105B2D66E4B6" }, { "b" : "7F84EF873000", "path" : "/usr/lib/x86_64-linux-gnu/libdb-5.3.so",
"elfType" : 3, "buildId" : "2B17894B4DF79DA6735BD54381B75402BD654796" }, { "b" : "7F84EF66D000",
"path" : "/usr/lib/x86_64-linux-gnu/sasl2/libcrammd5.so", "elfType" : 3, "buildId"
: "F956F817302B843D1FA74AF8577DDCF3CC4855B7" }, { "b" : "7F84EF468000", "path" : "/usr/lib/x86_64-linux-gnu/sasl2/libplain.so",
"elfType" : 3, "buildId" : "AAA34050DD1BAF7809DF19549571A2F082276782" }, { "b" : "7F84EF25F000",
"path" : "/usr/lib/x86_64-linux-gnu/sasl2/libntlm.so", "elfType" : 3, "buildId" : "11357A5DA0B160164C8DF2F4DB2B9E00B0540245"
}, { "b" : "7F84EF05A000", "path" : "/usr/lib/x86_64-linux-gnu/sasl2/libanonymous.so",
"elfType" : 3, "buildId" : "EAC878F70ADD404EF9E0EE9705ED015732F3F8F0" }, { "b" : "7F84EEE4C000",
"path" : "/usr/lib/x86_64-linux-gnu/sasl2/libdigestmd5.so", "elfType" : 3, "buildId"
: "F64BDE43D36E8005E4AB971AF5C9DC3BA56417AE" } ] }}
 mongod(_ZN5mongo15printStackTraceERSo+0x41) [0x555b96fd4741]
 mongod(+0x287BF3E) [0x555b96fd3f3e]
 mongod(+0x287BFD6) [0x555b96fd3fd6]
 libpthread.so.0(+0x12890) [0x7f84f50a4890]
 libc.so.6(gsignal+0xC7) [0x7f84f4cdfe97]
 libc.so.6(abort+0x141) [0x7f84f4ce1801]
 mongod(_ZN5mongo22invariantFailedWithMsgEPKcRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES1_j+0x0)
[0x555b95458a52]
 mongod(_ZNK5mongo13CollationSpec6toBSONEv+0x1D54) [0x555b96ed3a74]
 mongod(+0x1788E9D) [0x555b95ee0e9d]
 mongod(_ZN5mongo9PipelineD15prepareExecutorEPNS_16OperationContextEPNS_10CollectionERKNS_15NamespaceStringEPNS_8PipelineERKN5boost13intrusive_ptrINS_17ExpressionContextEEEbRKNSB_INS_18DocumentSourceSortEEESt10unique_ptrINS_36GroupFromFirstDocumentTransformationESt14default_deleteISL_EERKNS_11DepsTrackerERKNS_7BSONObjEPKNS_18AggregationRequestERKyPSS_S10_+0x805)
[0x555b95ee1b35]
 mongod(_ZN5mongo9PipelineD30buildInnerQueryExecutorGenericEPNS_10CollectionERKNS_15NamespaceStringEPKNS_18AggregationRequestEPNS_8PipelineE+0x348)
[0x555b95ee2d38]
 mongod(_ZN5mongo9PipelineD23buildInnerQueryExecutorEPNS_10CollectionERKNS_15NamespaceStringEPKNS_18AggregationRequestEPNS_8PipelineE+0x56A)
[0x555b95ee4fea]
 mongod(_ZN5mongo9PipelineD42buildAndAttachInnerQueryExecutorToPipelineEPNS_10CollectionERKNS_15NamespaceStringEPKNS_18AggregationRequestEPNS_8PipelineE+0x48)
[0x555b95ee5538]
 mongod(_ZN5mongo24MongoInterfaceStandalone40attachCursorSourceToPipelineForLocalReadERKN5boost13intrusive_ptrINS_17ExpressionContextEEEPNS_8PipelineE+0x18F)
[0x555b956cf37f]
 mongod(_ZN5mongo24MongoInterfaceStandalone28attachCursorSourceToPipelineERKN5boost13intrusive_ptrINS_17ExpressionContextEEEPNS_8PipelineE+0x24)
[0x555b956cd684]
 mongod(_ZN5mongo24MongoInterfaceStandalone12makePipelineERKSt6vectorINS_7BSONObjESaIS2_EERKN5boost13intrusive_ptrINS_17ExpressionContextEEENS_21MongoProcessInterface19MakePipelineOptionsE+0x8B)
[0x555b956ce1fb]
 mongod(_ZN5mongo20DocumentSourceLookUp13buildPipelineERKNS_8DocumentE+0x1BE) [0x555b968d458e]
 mongod(_ZN5mongo20DocumentSourceLookUp7getNextEv+0xF7) [0x555b968d4fb7]
 mongod(_ZN5mongo8Pipeline7getNextEv+0x3D) [0x555b9691c48d]
 mongod(_ZN5mongo18PipelineProxyStage11getNextBsonEv+0x35) [0x555b95eb5065]
 mongod(_ZN5mongo18PipelineProxyStage6doWorkEPm+0x46) [0x555b95eb4ed6]
 mongod(_ZN5mongo9PlanStage4workEPm+0x68) [0x555b95eb5618]
 mongod(_ZN5mongo16PlanExecutorImpl12_getNextImplEPNS_11SnapshottedINS_7BSONObjEEEPNS_8RecordIdE+0x230)
[0x555b95efd180]
 mongod(_ZN5mongo16PlanExecutorImpl7getNextEPNS_7BSONObjEPNS_8RecordIdE+0x4D) [0x555b95efd90d]
 mongod(+0x14AD78D) [0x555b95c0578d]
 mongod(_ZN5mongo12runAggregateEPNS_16OperationContextERKNS_15NamespaceStringERKNS_18AggregationRequestERKNS_7BSONObjERKSt6vectorINS_9PrivilegeESaISC_EEPNS_3rpc21ReplyBuilderInterfaceE+0x277F)
[0x555b95c0a08f]
 mongod(+0x14A57A5) [0x555b95bfd7a5]
 mongod(+0x11CF859) [0x555b95927859]
 mongod(+0x11D0F13) [0x555b95928f13]
 mongod(+0x11D1DCE) [0x555b95929dce]
 mongod(_ZN5mongo23ServiceEntryPointCommon13handleRequestEPNS_16OperationContextERKNS_7MessageERKNS0_5HooksE+0x540)
[0x555b9592a6a0]
 mongod(_ZN5mongo23ServiceEntryPointMongod13handleRequestEPNS_16OperationContextERKNS_7MessageE+0x3C)
[0x555b959186cc]
 mongod(_ZN5mongo19ServiceStateMachine15_processMessageENS0_11ThreadGuardE+0xEC)
[0x555b9592428c]
 mongod(_ZN5mongo19ServiceStateMachine15_runNextInGuardENS0_11ThreadGuardE+0x17F)
[0x555b9591fc0f]
 mongod(+0x11CAE8C) [0x555b95922e8c]
 mongod(_ZN5mongo9transport26ServiceExecutorSynchronous8scheduleESt8functionIFvvEENS0_15ServiceExecutor13ScheduleFlagsENS0_23ServiceExecutorTaskNameE+0x182)
[0x555b96703d52]
 mongod(_ZN5mongo19ServiceStateMachine22_scheduleNextWithGuardENS0_11ThreadGuardENS_9transport15ServiceExecutor13ScheduleFlagsENS2_23ServiceExecutorTaskNameENS0_9OwnershipE+0x10D)
[0x555b9591d62d]
 mongod(_ZN5mongo19ServiceStateMachine15_sourceCallbackENS_6StatusE+0x843) [0x555b959208c3]
 mongod(_ZN5mongo19ServiceStateMachine14_sourceMessageENS0_11ThreadGuardE+0x2E7)
[0x555b9591ecf7]
 mongod(_ZN5mongo19ServiceStateMachine15_runNextInGuardENS0_11ThreadGuardE+0xDB)
[0x555b9591fb6b]
 mongod(+0x11CAE8C) [0x555b95922e8c]
 mongod(+0x1FAC1BB) [0x555b967041bb]
 mongod(+0x260E874) [0x555b96d66874]
 libpthread.so.0(+0x76DB) [0x7f84f50996db]
 libc.so.6(clone+0x3F) [0x7f84f4dc288f]
-----  END BACKTRACE  -----


Также один раз появилась такая ошибка:

Command failed with error 13548: 'BufBuilder attempted to grow() to 240394258 bytes,
past the 64MB limit.' on server
    


Ответы

Ответ 1



После обращения на багтрекер mongodb выяснилось, что это связано с присутствием в одной объединяемой коллекции объекта "сollation" и отсутствие его в другой. Результат команды db.getCollectionInfos(); { "name" : "orders", "type" : "collection", "options" : { "collation" : { "locale" : "ru", "caseLevel" : false, "caseFirst" : "off", "strength" : 3, "numericOrdering" : false, "alternate" : "non-ignorable", "maxVariable" : "punct", "normalization" : false, "backwards" : false, "version" : "57.1" } }, "info" : { "readOnly" : false, "uuid" : UUID("269bd5be-6e3a-49f6-af14-0ce3f1a31212") }, "idIndex" : { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "fdatabase.orders", "collation" : { "locale" : "ru", "caseLevel" : false, "caseFirst" : "off", "strength" : 3, "numericOrdering" : false, "alternate" : "non-ignorable", "maxVariable" : "punct", "normalization" : false, "backwards" : false, "version" : "57.1" } } }, { "name" : "items", "type" : "collection", "options" : { }, "info" : { "readOnly" : false, "uuid" : UUID("808700ba-bca9-4ae4-88b9-6a42e32deff7") }, "idIndex" : { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "fdatabase._items" } } Это было принято как баг и передано команде разработки на рассмотрение. После создания новой коллекции orders без сollation и переноса туда данных со старой коллекции, падения прекратились.

воскресенье, 12 января 2020 г.

Как организовать полноценный рабочий экземпляр монго дб на андроид

#android #mongodb #cordova


Как организовать полноценный рабочий экземпляр монго дб на андроид со всеми фишками
самой монги - как то геопоиск, междокументные ссылки и тд и тп, при использовании нативного апи.
Цель поиметь частичную реплику базы данных, синхронизируемую посредством wamp в реалтайме,
и собственной синхронизационной процедуры для офлайн изменений.
Может быть кото-то реализовывал запуск монги через cordova или другой инструмент?  
    


Ответы

Ответ 1



Не думаю, что возможно запустить полноценно рабочий экземпляр монги на Android. Его и в списке поддерживаемых платформ нет. Да и дело даже не в этом. MongoDB не сможет нормально функционировать на подобных системах с таким маленьким объёмом доступной памяти для приложений. Были, правда, обсуждения в своё время. Можно попробовать самим собрать билд. UPD: если вам не обязателен MongoDB, то можно использовать Couchbase Lite.

пятница, 10 января 2020 г.

Удаление словаря из массива Mongodb по номеру (pymongo)

#python #mongodb #pymongo


В коллекции есть массив со словарями:

{
"_id": {
    "$oid": "576502aca43aa11ca48bb8d5"
},
"event_name": "Тестовое",
"participants": [
    {
        "name": "Участник 1",
        "start_debt": 2500,
        "income": 0,
        "debt": 2500
    },
    {
        "name": "Участник 2",
        "start_debt": 2500,
        "income": 0,
        "debt": 2500
    },
    {
        "name": "Участник 3",
        "start_debt": 2500,
        "income": 0,
        "debt": 2500
    },
    {
        "name": "Участник 3",
        "start_debt": 2500,
        "income": 0,
        "debt": 2500
    }
],
"debt": 10000,
"income": 0,
"budget": 10000}


Нужно удалить элемент из массива(словарь) именно по порядковому номеру.

Пытался сделать таким образом:

data_base.update_one({"_id": ObjectId(event_id)},
                                 {'$pull': {'participants': 2}})


Естественно результата не добился.
    


Ответы

Ответ 1



Напрямую удалить элемент по индексу пока нельзя, смотрите ишью https://jira.mongodb.org/browse/SERVER-1014. Но можно обойти с помощью двух последовательных команд: mongo.db.collection.update({}, {'$unset': {'participants.2':1}}) mongo.db.collection.update({}, {'$pull': {'participants': None}}) Сначала заменяем нужный элемент (в данном случае с индексом 2) на null, затем второй командой удаляем его. Большой минус - действия не атомарные, и после выполнения первого, какое то время в массиве будет элемент со значением null. Если это критично, то верный способ это вручную считать/модифицировать/записать документ.

пятница, 27 декабря 2019 г.

Первый опыт в node.js Можно ли не переделывая с нуля получить сносный результат?

#nodejs #mongodb #инспекция_кода #express #mongoose


Мой первый опыт программирования, если не считать студенческих лабораторных на Delphi(и
те были очень давно). 

Цель: "приложение" которое на первой странице выдает кликабельный список из имен
юзеров(имена берем в mongodb), а при клике на юзера перебрасывает на другую страницу,
где уже отображает(беря из базы) подробные сведения о выбранном юзере.
Основательно переписал, получил вот это. 

Вопросы:


Общая структура более-менее адекватна? Дорабатывать имеющееся или же переделывать
с нуля? 
В модуле userModel я подключаюсь к базе данных. Там предусмотрена простейшая обработка
ошибки в виде сообщения в консоль. Как бы мне сделать так, чтобы эта ошибка попадала
в express и я мог вывести в браузере объект ошибки? 




//app.js:

var express = require('express');
var app = express();

var router = require('./router/router');
app.use(router);
app.listen(3000, function() {
  console.log('Listening on port 3000!\nDatabase on mlab.com');
});

//router.js:
var express = require('express');
GetFirstPage = require('../lib/GetPages').firstPage;
GetSecondPage = require('../lib/GetPages').secondPage;

var router = express.Router();
router.get('/', GetFirstPage);
router.get('/user?:id', GetSecondPage);
router.use(express.static('public'));
module.exports = router;
//userModel:
const mongoose = require('mongoose');
mongoose.connect(require('../credentials').mongo, function(err) {
  if (err) console.log('Error database connection\n', err)
});


const userShema = mongoose.Schema({
  name: String,
  age: String,
  disciplines: String,
});

module.exports = mongoose.model('User', userShema);

//GetPages.js:
var express = require('express');
var app = express();
var _ = require('underscore');
const User = require('./exportFromDB').user;
const NamesList = require('./exportFromDB').namesList;

module.exports.firstPage = function(req, res) {
  Promise.all([
    NamesList(), readMainPage()
  ]).then(function(results) {
    const list = results[0].map(function(item) {
      return item.name
    })
    res.send(results[1]({
      'list': list
    }))
  })
}

module.exports.secondPage = function(req, res) {
  Promise.all([
    User(decodeURIComponent(req.query.id)), readSecondPage()
  ]).then(function(results) {
    res.send(results[1]({
      name: results[0][0].name,
      age: results[0][0].age,
      disciplines: results[0][0].disciplines
    }))
  })
}

function readMainPage() {
  const myFile = require('../lib/exportFile').mainPage;
  return myFile();
}

function templateMainPage(template) {
  res.send(template({
    'list': List
  }))
}

function readSecondPage() {
  const myFile = require('../lib/exportFile').secondPage;
  return myFile();
}
//ExportDB.js
userModel = require('./userModel');


module.exports.namesList = () => {
  return new Promise(function(resolved, rejected) {
    userModel.find({}, 'name -_id', function(err, data) {
      resolved(data)
    })
  })
}
module.exports.user = (url) => {
  return new Promise(function(resolved, rejected) {
    userModel.find({
      name: url
    }, function(err, data) {
      resolved(data)
    })
  })
}



    


Ответы

Ответ 1



Как-то так стандартно выглядит запрос страницы всех юзеров: app.get('/', function(req, res) { users.find({}, (err, docs) => { res.locals.users = docs; res.render('list'); }; }; А в шаблоне страницы списка - юзеры выводятся в цикле each user in users, где каждый обёртывается в ссылку с атрибутом такого вида href="/users/#{user._id}" (или какой-там у вас синтаксис шаблонизатора) А запрос страниц отдельных юзеров - app.get('/users/:id', ..., и в его обработчике, в объекте запроса значением параметра req.params.id будет айдишник юзера в базе, по которому он легко и запрашивается - app.get('/users/:id', function(req, res) { users.find({_id: req.params.id}, (err, result) => { res.locals.user = result; res.render('user'); }; }; Шаблон страницы получил объект юзера - user._id user.name user.age и т.д. Всего и делов - спасибо ТиДжею Каравайчуку (или как там его) за Express.

среда, 25 декабря 2019 г.

Автостарт сервиса после полного старта mongodb

#linux #ubuntu #mongodb #systemd


Система: ubuntu 16.04.1 (для запуска сервисов используется systemd).

Имеем: приложение-сервис, которое зависит от mongodb. Приложение и mongodb запускаются
автоматически, на старте ubuntu. В .service файле приложения прописана зависимость:

After=network.target mongod.service


При этом, вероятно, из-за того, что mongodb сразу после старта ещё не готова принимать
подключения, приложение падает с ошибкой "невозможно подключиться к бд".

Каким образом лучше выполнить задержку до полного старта mongodb, либо другим способом
определить готовность mongodb используя возможности systemd?
    


Ответы

Ответ 1



В этом случае воспользуйтесь ExecStartPost и netcat: ExecStart= ExecStartPost=/bin/sleep 1s ExecStartPost=/usr/bin/nc -z host port Где host port - адрес и порт mongodb. systemd будет ожидать выполнения всех команд до запуска зависимых сервисов. В случае если время старта может "плавать" поможет: until [[ $(nc -z ) -eq 1 ]]; do sleep 1s; done until будет вызывать sleep до тех пор пока netcat возвращает -1. ExecStartPre и ExecStartPost часть жизненного цикла запуска unita ExecStartPre=, ExecStartPost= Additional commands that are executed before or after the command in ExecStart=, respectively. Syntax is the same as for ExecStart=, except that multiple command lines are allowed and the commands are executed one after the other, serially. If any of those commands (not prefixed with "-") fail, the rest are not executed and the unit is considered failed. ExecStart= commands are only run after all ExecStartPre= commands that were not prefixed with a "-" exit successfully. ExecStartPost= commands are only run after the service has started successfully, as determined by Type= (i.e. the process has been started for Type=simple or Type=idle, the process exits successfully for Type=oneshot, the initial process exits successfully for Type=forking, "READY=1" is sent for Type=notify, or the BusName= has been taken for Type=dbus). Note that ExecStartPre= may not be used to start long-running processes. All processes forked off by processes invoked via ExecStartPre= will be killed before the next service process is run. Note that if any of the commands specified in ExecStartPre=, ExecStart=, or ExecStartPost= fail (and are not prefixed with "-", see above) or time out before the service is fully up, execution continues with commands specified in ExecStopPost=, the commands in ExecStop= are skipped. В случае если между unit'ами указана зависимость Before или After systemd откладывает старт зависящего сервиса до тех пор пока другой не запустится: Before=, After= A space-separated list of unit names. Configures ordering dependencies between units. If a unit foo.service contains a setting Before=bar.service and both units are being started, bar.service's start-up is delayed until foo.service is started up. Note that this setting is independent of and orthogonal to the requirement dependencies as configured by Requires=. It is a common pattern to include a unit name in both the After= and Requires= option, in which case the unit listed will be started before the unit that is configured with these options. This option may be specified more than once, in which case ordering dependencies for all listed names are created. After= is the inverse of Before=, i.e. while After= ensures that the configured unit is started after the listed unit finished starting up, Before= ensures the opposite, i.e. that the configured unit is fully started up before the listed unit is started. Note that when two units with an ordering dependency between them are shut down, the inverse of the start-up order is applied. i.e. if a unit is configured with After= on another unit, the former is stopped before the latter if both are shut down. Given two units with any ordering dependency between them, if one unit is shut down and the other is started up, the shutdown is ordered before the start-up. It doesn't matter if the ordering dependency is After= or Before=. It also doesn't matter which of the two is shut down, as long as one is shut down and the other is started up. The shutdown is ordered before the start-up in all cases. If two units have no ordering dependencies between them, they are shut down or started up simultaneously, and no ordering takes place.

среда, 18 декабря 2019 г.

Поиск документов, значение ключа у которых не выходит за рамки полученного массива

#mongodb #aggregation_framework #mongodb_query


Мне нужно получить массив от пользователя и сделать выборку из базы по следующему
принципу:
если полученный массив такой

animals = ['cat', 'dog', 'penguin']


то мне нужны документы где

animals = ['cat', 'dog', 'penguin']
animals = ['cat', 'dog']
animals = ['cat' 'penguin']
и т.д.


Подскажите, пожалуйста, как вообще называются такие выборки и как их правильно делать
в mongodb.
    


Ответы

Ответ 1



Если запрос достаточно сложный, и базовых средств либо знаний не хватает, то всегда можно воспользоваться механизмом $where. То есть можно написать сложную логику получения данных, включая if-ы, и вернуть результат, чего в обычных базах данных добиться очень и очень сложно (имею в виду условия и циклы внутри SQL-запросов). Синтаксис прост — в качестве параметра передаётся функция: db.foo.find({$where : функция}) При этом используется объект (переменная) this, по сути — курсор, у которой можно получать свойства. Функция должна вернуть true или false, что означает, попадёт строка в выборку или нет. Вот пример из википедии: db.foo.find({$where : function() { return this.x == this.y; }}) При этом также можно использовать вложенные OR или AND, как в классических SQL-запросах: db.foo.find({$where : function() { if((this.cost>5 && this.cost<10 )|| (this.is_hidden != 1) || (this.link == this.url)){ return true; } return false; }}) Таким образом, курсор пробегает по базе, и выполняет проверки. разумеется, всё это можно ограничивать лимитами на количество строк, $where — всего лишь ключ в массиве параметров запроса. Необходимо понимать, что это всё-таки медленне, чем обычные запросы, но всё равно достаточно быстро. скопировано отсюда по наводке из комментария автора вопроса.

Ответ 2



Я полагаю, у вас есть следующие документы в вашей коллекции. { "_id" : ObjectId("56ac7281ebc094e3677b809f"), "animals" : [ "rat", "cat" ] }, { "_id" : ObjectId("56ac7281ebc094e3677b80a0"), "animals" : [ "dog", "cat", "penguin" ] }, { "_id" : ObjectId("56ac7281ebc094e3677b80a1"), "animals" : [ "dog" ] }, { "_id" : ObjectId("56ac7281ebc094e3677b80a2"), "animals" : [ "cat", "dog" ] }, { "_id" : ObjectId("56ac7281ebc094e3677b80a3"), "animals" : [ "dog", "penguin" ] } и массив "animals": var animals = [ "cat", "dog", "penguin" ]; Лучший способ это делать это используя .aggregate() метод который обеспечивает доступ к агрегации цепочке. Первый этап в цепочке это $match где вы отфильтроваете документы, которые не имеют какой-либо элемента в массиве "animals". Это также уменьшает количество документов, которые будут обрабатываться в следующей стадии. Следующий и последний этап — это $redact. Здесь нужно использовать оператор $setIsSubset точно делает что мы хотим; он возврашает true если все элементы первого множество появляются во втором множество, в том числе, когда первый множеств равен второй; и также потому MongoDB не позволяет использовать $in в $cond. Конечно $$KEEP и $$PRUNE являются системные переменные. db.collection.aggregate([ { "$match": { "animals": { "$in": animals } } }, { "$redact": { "$cond": [ { "$setIsSubset": [ "$animals", animals ] }, "$$KEEP", "$$PRUNE" ] }} ]) Это запрос возврашает следующий результат: { "_id" : ObjectId("56ac7281ebc094e3677b80a0"), "animals" : [ "dog", "cat", "penguin" ] } { "_id" : ObjectId("56ac7281ebc094e3677b80a1"), "animals" : [ "dog" ] } { "_id" : ObjectId("56ac7281ebc094e3677b80a2"), "animals" : [ "cat", "dog" ] } { "_id" : ObjectId("56ac7281ebc094e3677b80a3"), "animals" : [ "dog", "penguin" ] } Здесь вам не нужно использовать оператор $where поскольку он вызовет падение производительности. $where evaluates JavaScript and cannot take advantage of indexes. Therefore, query performance improves when you express your query using the standard MongoDB operators (e.g., $gt, $in). In general, you should use $where only when you can’t express your query using another operator. If you must use $where, try to include at least one other standard query operator to filter the result set. Using $where alone requires a table scan. Конечно $redact не использует индексы. Он даже делает сканирования все документы в коллекции но более лучше.

суббота, 14 декабря 2019 г.

Как обновить несколько элементов в массиве?

#mongodb #aggregation_framework #mongodb_query


Необходимо обновить одним запросом несколько данных. Вот пример запроса:

db.coll.update(
  { article: 100500 },
  {
    $set: { a: 555 },
    $pull: { arr: { t: { $lt: 20 } } }
  }
);


А вот пример самого документа:

{
  article: 100500,
  a: 400,
  arr: [
    { t: 30, b: 12, n: 90 },
    { t: 10, b: 16, n: 60 }
  ]
}


Мой запрос:


Обновляет значение a на 555.
Удаляет все элементы массива arr, где t < 20.


Суть вопроса:
Надо обновить значения b в маccве arr. То есть, везде где n == 90, значение b надо
поменять на 777. Как можно дополнить этот запрос, чтобы "убить сразу 3-х зайцев"? 

В итоге должен получиться такой документ:

{
  article: 100500,
  a: 555, /* Тут было: 400 */
  arr: [
    { t: 30, b: 777, n: 90 },
    /* Тут был элемент массива */
  ]
}

    


Ответы

Ответ 1



Я полагаю, у вас есть следующие документы в вашей коллекции. { "_id" : ObjectId("56b71025973d202a52a5e650"), "article" : 100500, "a" : 400, "arr" : [ { "t" : 30, "b" : 12, "n" : 90 }, { "t" : 20, "b" : 16, "n" : 60 } ] }, { "_id" : ObjectId("56b7102b973d202a52a5e651"), "article" : 100500, "a" : 400, "arr" : [ { "t" : 0, "b" : 12, "n" : 90 }, { "t" : 10, "b" : 16, "n" : 60 } ] }, { "_id" : ObjectId("56b710d4973d202a52a5e652"), "article" : 100500, "a" : 400, "arr" : [ { "t" : 30, "b" : 12, "n" : 90 }, { "t" : 27, "b" : 16, "n" : 32 } ] } Прежде всего вы должны знать, что это не возможно, чтобы обновить более одного элемента в массиве используя метод update() даже с опцей multi: true или используя метод updateMany(); и все логики позади, что вы пытаетесь сделать; делать вещи более сложнее. Лучший способ это делать это используя Bulk Операции. Решение для MongoDB версия 3.2 или новее: MongoDB 3.2 не рекомендуется Bulk() и связанные с ним методы. Нужно использовать метод .bulkWrite() Здесь у нас есть два варианта: Нужно использовать агрегация чтотбы уменшать количество докуменьов которые нужно обновить. здесь в цепочке нужно только один этап: $project где мы используем оператор $filter. let requests = []; db.collection.aggregate([ { "$project": { "deleteElements": { "$filter": { "input": "$arr", "as": "del", "cond": { "$lt": [ "$$del.t", 12 ] } } }, "updateElements": { "$filter": { "input": "$arr", "as": "upd", "cond": { "$and": [ { "$gte": [ "$$upd.t", 12 ] }, { "$eq": [ "$$upd.n", 90 ] } ] } } } }} ]).forEach(function(document) { document.deleteElements.forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.t": element.t }, "update": { "$pull": { "arr": element } } } } ); }); document.updateElements.forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.t": element.n }, "update": { "$set": { "arr.$.b": 777 } } } } ); }); requests.push( { "updateOne": { "filter": { "_id": document._id }, "update": { "$set": { "a": 555 } } } } ); }) db.collection.bulkWrite(requests) Используя метод .find() db.collection.find({"article": 100500}).snapshot().forEach(function(document) { document.arr.filter(function(arr) { return arr.t < 12; }).forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.t": { "$lt": 12 }}, "update": { "$pull": { "arr": element } } } } ); }); document.arr.filter(function(arr) { return arr.n === 90; }).forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.n": 90 }, "update": { "$set": { "arr.$.b": 777 } } } } ); }); requests.push( { "updateOne": { "filter": { "_id": document._id }, "update": { "$set": { "a": 555 } } } } ); }) db.collection.bulkWrite(requests); Решение для MongoDB версии 2.6 или новее: var bulk = db.collection.initializeOrderedBulkOp(); var count = 0; db.collection.find({"article": 100500}).snapshot().forEach(function(document) { document.arr.filter(function(arr) { return arr.t < 12; }).forEach(function(element) { bulk.find({ "_id": document._id, "arr.t": { "$lt": 12 } } ).updateOne({ "$pull": { "arr": element } }); count++; }); document.arr.filter(function(arr) { return arr.n === 90; }).forEach(function(element) { bulk.find({ "_id": document._id, "arr.n": 90 }).updateOne({ "$set": { "arr.$.b": 777 } }); count++; }); bulk.find( { "_id": document._id } ).updateOne( { "$set": { "a": 555 } } ); count++; if (count % 1000 === 0) { // Выпольнить после 1000 операции bulk.execute(); bulk = db.collection.initializeOrderedBulkOp(); } }) // Очистить очереди if (count > 0) { bulk.execute(); } Результать { "_id" : ObjectId("56b71025973d202a52a5e650"), "article" : 100500, "a" : 555, "arr" : [ { "t" : 30, "b" : 777, "n" : 90 }, { "t" : 20, "b" : 16, "n" : 60 } ] } { "_id" : ObjectId("56b7102b973d202a52a5e651"), "article" : 100500, "a" : 555, "arr" : [ ] } { "_id" : ObjectId("56b710d4973d202a52a5e652"), "article" : 100500, "a" : 555, "arr" : [ { "t" : 30, "b" : 777, "n" : 90 }, { "t" : 27, "b" : 16, "n" : 32 } ] }

среда, 11 декабря 2019 г.

Горизонтальное масштабирование

#php #yii #mongodb #highload #масштабирование


Для одного из PHP + MongoDB проектов возникла необходимость осуществления горизонтального
масштабирования.


Учитывая, что будет использоваться несколько серверов, как лучше реализовать актуальность
своих же скриптов? Разные мелочи появляются довольно часто, как бы их из одного централизованного
хранилища сразу везде обновлять? sshfs, или gluster, или есть более простые способы?
В идеале хотелось бы иметь где-то директорию с ядром проекта, которое бы использовалось
напрямую остальными серверами.
Кэширование сейчас организовано в файловой системе, но, как я понимаю, будет необходимо
делать его общим для всех серверов. Как это делать лучше? Завести ещё одну БД под кэш,
или как-то ещё "выкручиваться"? Особенность у нас - в кэше есть данные общим объёмом
в несколько гигабайт, которые изменяются от силы раз в год, а используются чуть ли
не каждую минуту, именно из-за этого когда-то кэш не стали делать в redis. Как с такими
данными быть, тоже в БД? И какую БД для этого выбрать?
Правильно ли я понимаю, что при горизонтальном масштабировании сессии тоже 
необходимо хранить в БД?

    


Ответы

Ответ 1



Использовать сетевое хранилище для исходников - не самая лучшая идея. Каждый раз когда появляются разные мелочи - они должны пройти тестирование в отдельном окружении и только после этого следует использовать скрипт развертывания (deployment) актуальной версии и только на одном сервере, - после чего при помощи a/b-тестирования убедиться, что все работает как нужно. И только после того как все изменения протестированы, - запускать скрипт развертывания на остальных серверах. Использование файлового хранилища для исходников возможно, но это выглядит как неоправданная жертва стабильности в угоду удобству. Чем не подошел кэш в redis? - Несколько ГБ данных не создаст для него проблемы. Или вы имеете в виду, что одна запись в кэшэ занимает несколько ГБ ? - В таком случае следует разделить легкий и тяжелый кэш на раздельные сервисы. Нет. При горизонтальном масштабировании вы можете привязать пользователя к определенному серверу с которым он будет работать, в частности это используется для a/b-тестирования. В любом случае хранить сессии в реляционной БД не нужно, - они очень хорошо лежат в memcached.

вторник, 10 декабря 2019 г.

Как оставить в массиве элемент с максимальным значением

#mongodb #aggregation_framework #mongodb_query


У меня следующие документы в коллекции

{
   "_id": 1,
   "values":[
      {
         "value1":10,
         "value2":12,
         "value3":30
      },
      {
         "value1":20,
         "value2":12,
         "value3":100
      },
      {
         "value1":30,
         "value2":14,
         "value3":50
      }
   ]
},
{
   "_id": 2,
   "values":[
      {
         "value1":10,
         "value2":12,
         "value3":60
      },
      {
         "value1":20,
         "value2":12,
         "value3":80
      },
      {
         "value1":30,
         "value2":14,
         "value3":70
      }
   ]
}


Мне нужно оставить один документ с одним элементом в массиве по следующим критериям:

values.value1 = 20
values.value2 = 12
values.value3  // максимальное значение из всех значений values.value3 во всех документах


Например, по вышеуказанным критериям должен получиться такой документ:

{
   "_id": 1,
   "values":[
      {
         "value1":20,
         "value2":12,
         "value3":100
      }
   ]
}


Также, подойдет решение, просто сортирующие документы и элементы по указанным критериям.
Чтобы первым документом был тот, в котором значение values.value3 максимально из возможных
и первым элементом в массиве был объект с максимальным значением. Например:

{
   "_id": 1,
   "values":[
     {
         "value1":20,
         "value2":12,
         "value3":100
      },
      {
         elements...
      }
   ]
},
{
   "_id": 2,
   "values":[
      {
         elements...
      }
   ]
}


Сделать это у меня получается, но я использую $match, $unwind, $group, $redact, $sort
по несколько раз. Может быть кто-то предложит более правильную реализацию.
    


Ответы

Ответ 1



Лучший способ это запустить два запроса. Первый, чтобы нашел максимальное значение и второй, чтобы остался только документ, где value3 равно этому значению. Решение для MongoDB версия 3.2 или новее: Начиная с версии 3.2 можно использовать оператор $max, который возвращает максимальное значение для каждого документа в $project этапе. Оператор $map здесь возвращает массив value3. Следующий этап в цепочке — это $group, где нужно группировать документы и возвращать максимальное значение. var result = db.collection.aggregate([ { "$project": { "maxVal": { "$max": { "$map": { "input": "$values", "as": "value", "in": "$$value.value3" } } } } }, { "$group": { "_id": null, "mval": { "$max": "$maxVal" } } } ]); Поскольку метод .aggregate() возвращает курсор, нужно использовать метод toArray() и оператор [] для получения значения. var maximumValue = result.toArray()[0]['mval']; Теперь можно использовать это значение, чтобы оставить в массиве только элемент с максимальным значением. Для этого нужно использовать оператор $filter db.collection.aggregate( [ { "$match": { "values.value3": maximumValue } }, { "$project": { "values": { "$filter": { "input": "$values", "as": "value", "cond": { "$eq": [ "$$value.value3", maximumValue ] } } } } } ]) Решение для MongoDB версии 2.6 или новее: Решение для версий с 2.6 по 3.2 менее эффективно. Сначала в первом запросе нужно денормализовать массив value3 сразу после $project, используя оператор $unwind. Последний этап в цепочке это $group, где группируем документы и возвращаем максимальное значение value3 var result = db.collection.aggregate([ { "$project": { "value3": { "$map": { "input": "$values", "as": "value", "in": "$$value.value3" } } } }, { "$unwind": "$value3" }, { "$group": { "_id": null, "mval": { "$max": "$value3" } } } ]); var maximumValue = result.toArray()[0]['mval']; Чтобы оставить в массиве только элемент с максимальным значением, у нас есть два варианта: Используя оператор $redact db.collection.aggregate( [ { "$match": { "values.value3": maximumValue } }, { "$redact": { "$cond": [ { "$or": [ { "$eq": [ "$value3", maximumValue ] }, { "$not": "$value3" } ]}, "$$DESCEND", "$$PRUNE" ] }} ]) Используя оператор $project и $setDifference db.collection.aggregate( [ { "$match": { "values.value3": maximumValue } }, { "$project": { "values": { "$setDifference": [ { "$map": { "input": "$values", "as": "value", "in": { "$cond": [ { "$eq": [ "$$value.value3", maximumValue ] }, "$$value", false ] } }}, [false] ] } }} ])

среда, 10 июля 2019 г.

Mongodb aggregate (агрегация/группировка товаров)

Решил поупражняться с парсерами и работой с mongodb, но столкнулся со следующей проблемой.
Имеется коллекция с товарами. Для примера возьмем следующие документы из нее:
{title: 'acer aspire 6420', source: 'amazon', price: 300} {title: 'acer aspire 6420', source: 'ebay', price: 320}
Из них необходимо получить следующий документ:
{title: 'acer aspire 6420', amazon: 300, ebay: 320}
то есть сгруппировать по названию и вывести цену в каждом из магазинов.
В ходе разбирательства написал следующий код на питоне:
from bson.code import Code
reducer = Code(""" function(origin, res){ res[origin.source] = origin.price } """)
db.products.group(key={"source":1, 'title': 1, 'price': 1}, condition={'title': 'acer aspire 6420'}, initial={}, reduce=reducer)
но по итогу получаю вот такой результат:
{title: 'acer aspire 6420', source: 'amazon', price: 300, amazon: 300, ebay: 320} {title: 'acer aspire 6420', source: 'ebay', price: 320, amazon: 300, ebay: 320}
Подскажите, пожалуйста, в какую сторону дальше копать или как это реализовать, чтобы результат получился таким:
{title: 'acer aspire 6420', amazon: 300, ebay: 320}
Я гуглил и читал документацию, правда. Просто не очень понимаю как это все правильно связать вместе.


Ответ

Вариант с aggregation framework (для mongoshell):
db.products.aggregate([ {$match: {title: "acer aspire 6420"}}, {$project: {_id: 0, title: 1, price: {source: "$source", value: "$price"} }}, {$group: {_id: "$title", prices: {$push: "$price"}}} ])
Что дает на выходе:
{ "_id" : "acer aspire 6420", "prices" : [ { "source" : "amazon", "value" : 300 }, { "source" : "ebay", "value" : 320 } ] }
Первая операция фильтрует по названию (title) товара, следующая формирует поле price в виде объекта с двумя полями - source и value, и последняя операция группирует по title, добавляя все варианты цен в создаваемое поле-массив prices
Т.к. у вас по условию задачи source должен быть именем поля в результате, а пока в mongodb aggregation framework поддержки динамических имен для создаваемых полей нет (https://jira.mongodb.org/browse/SERVER-5947), то можно пройтись по результату с помощью map
db.products.aggregate([ {$match: {title: "acer aspire 6420"}}, {$project: {_id: 0, title: 1, price: {source: "$source", value: "$price"} }}, {$group: {_id: "$title", prices: {$push: "$price"}}} ]).map(function(e) { var r = {} r.title = e._id; e.prices.forEach(function(i){r[i.source] = i.value}); return r; })
Что даст на выходе:
[ { "title" : "acer aspire 6420", "amazon" : 300, "ebay" : 320 } ]
В этом случае есть вероятность (в отличии от первого варианта) потерять информацию, если у вас, например, для amazon есть две разных цены.
Для питона, думаю, сможете сделать по аналогии.

пятница, 5 июля 2019 г.

Подтверждение записи данных в mongoDB

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


Ответ

Для этой цели в MongoDB специально введено понятние Write Concern. Выдержка из документации: write concern Specifies whether a write operation has succeeded. Write concern allows your application to detect insertion errors or unavailable mongod instances. For replica sets, you can configure write concern to confirm replication to a specified number of members. See Write Concern Дословно: Указывает, успешно ли выполнилась операция записи. "Write concern" позволяет вашим приложениям выявлять ошибки вставки или недоступности mongod. Для replica-set вы можете задать write concern, чтобы подтверждать репликацию в заданное число реплик. Существует определенный набор значений для этого параметра: Unacknowledged Acknowledged (by default) Journaled Replica Acknowledged По умолчанию драйвером используется Acknowledged уровень - mongod в этом случае будет сообщать клиенту о результатах записи. Т.е. клиент может отловить сетевые ошибки , получить сообщение duplicate key или другую ошибку. (Всё расписано в документации). Значение write concern'а в драйвере можно поменять в классе MongoClient

среда, 17 апреля 2019 г.

MongoDB, поиск по регулярному выражению

Добрый день! В документе есть поле size (строка) вида 134-140, 140-146 и тп. Делаю запрос
var s = "134"; var reg = new RegExp (`[${s}]`, "i"); collection.find({size:{$regex:reg}}).toArray(function(err, result){ console.log(result); });
По идее, должно вернуть все документы, где в поле size встречается цифры 134 (точнее строка). Но возвращает абсолютно все документы. Что я делаю не так?
П.С. после многочисленных тестов я определил, что возвращаются не все документы, а только те, где встречается хотя бы один символ из регулярного выражения. В данном случае 134. Так, будто квадратных скобок нет. Версия MongoDB-сервера 3.0, модуль версии 3.0


Ответ

var reg = /134/; collection.find({ size: { $regex: reg, $options: 'i' } })
UPD:
var s = "134"; var reg = ".*" + s ".*"; collection.find({ size: { $regex: reg, $options: 'i' } })

понедельник, 25 февраля 2019 г.

Удаление словаря из массива Mongodb по номеру (pymongo)

В коллекции есть массив со словарями:
{ "_id": { "$oid": "576502aca43aa11ca48bb8d5" }, "event_name": "Тестовое", "participants": [ { "name": "Участник 1", "start_debt": 2500, "income": 0, "debt": 2500 }, { "name": "Участник 2", "start_debt": 2500, "income": 0, "debt": 2500 }, { "name": "Участник 3", "start_debt": 2500, "income": 0, "debt": 2500 }, { "name": "Участник 3", "start_debt": 2500, "income": 0, "debt": 2500 } ], "debt": 10000, "income": 0, "budget": 10000}
Нужно удалить элемент из массива(словарь) именно по порядковому номеру.
Пытался сделать таким образом:
data_base.update_one({"_id": ObjectId(event_id)}, {'$pull': {'participants': 2}})
Естественно результата не добился.


Ответ

Напрямую удалить элемент по индексу пока нельзя, смотрите ишью https://jira.mongodb.org/browse/SERVER-1014
Но можно обойти с помощью двух последовательных команд:
mongo.db.collection.update({}, {'$unset': {'participants.2':1}}) mongo.db.collection.update({}, {'$pull': {'participants': None}})
Сначала заменяем нужный элемент (в данном случае с индексом 2) на null, затем второй командой удаляем его.
Большой минус - действия не атомарные, и после выполнения первого, какое то время в массиве будет элемент со значением null. Если это критично, то верный способ это вручную считать/модифицировать/записать документ.

понедельник, 3 декабря 2018 г.

Первый опыт в node.js Можно ли не переделывая с нуля получить сносный результат?

Мой первый опыт программирования, если не считать студенческих лабораторных на Delphi(и те были очень давно).
Цель: "приложение" которое на первой странице выдает кликабельный список из имен юзеров(имена берем в mongodb), а при клике на юзера перебрасывает на другую страницу, где уже отображает(беря из базы) подробные сведения о выбранном юзере. Основательно переписал, получил вот это.
Вопросы:
Общая структура более-менее адекватна? Дорабатывать имеющееся или же переделывать с нуля? В модуле userModel я подключаюсь к базе данных. Там предусмотрена простейшая обработка ошибки в виде сообщения в консоль. Как бы мне сделать так, чтобы эта ошибка попадала в express и я мог вывести в браузере объект ошибки?
//app.js: var express = require('express'); var app = express(); var router = require('./router/router'); app.use(router); app.listen(3000, function() { console.log('Listening on port 3000!
Database on mlab.com'); }); //router.js: var express = require('express'); GetFirstPage = require('../lib/GetPages').firstPage; GetSecondPage = require('../lib/GetPages').secondPage; var router = express.Router(); router.get('/', GetFirstPage); router.get('/user?:id', GetSecondPage); router.use(express.static('public')); module.exports = router; //userModel: const mongoose = require('mongoose'); mongoose.connect(require('../credentials').mongo, function(err) { if (err) console.log('Error database connection
', err) }); const userShema = mongoose.Schema({ name: String, age: String, disciplines: String, }); module.exports = mongoose.model('User', userShema); //GetPages.js: var express = require('express'); var app = express(); var _ = require('underscore'); const User = require('./exportFromDB').user; const NamesList = require('./exportFromDB').namesList; module.exports.firstPage = function(req, res) { Promise.all([ NamesList(), readMainPage() ]).then(function(results) { const list = results[0].map(function(item) { return item.name }) res.send(results[1]({ 'list': list })) }) } module.exports.secondPage = function(req, res) { Promise.all([ User(decodeURIComponent(req.query.id)), readSecondPage() ]).then(function(results) { res.send(results[1]({ name: results[0][0].name, age: results[0][0].age, disciplines: results[0][0].disciplines })) }) } function readMainPage() { const myFile = require('../lib/exportFile').mainPage; return myFile(); } function templateMainPage(template) { res.send(template({ 'list': List })) } function readSecondPage() { const myFile = require('../lib/exportFile').secondPage; return myFile(); } //ExportDB.js userModel = require('./userModel'); module.exports.namesList = () => { return new Promise(function(resolved, rejected) { userModel.find({}, 'name -_id', function(err, data) { resolved(data) }) }) } module.exports.user = (url) => { return new Promise(function(resolved, rejected) { userModel.find({ name: url }, function(err, data) { resolved(data) }) }) }


Ответ

Как-то так стандартно выглядит запрос страницы всех юзеров:
app.get('/', function(req, res) { users.find({}, (err, docs) => { res.locals.users = docs; res.render('list'); }; };
А в шаблоне страницы списка - юзеры выводятся в цикле each user in users, где каждый обёртывается в ссылку с атрибутом такого вида href="/users/#{user._id}" (или какой-там у вас синтаксис шаблонизатора)
А запрос страниц отдельных юзеров - app.get('/users/:id', ..., и в его обработчике, в объекте запроса значением параметра req.params.id будет айдишник юзера в базе, по которому он легко и запрашивается -
app.get('/users/:id', function(req, res) { users.find({_id: req.params.id}, (err, result) => { res.locals.user = result; res.render('user'); }; };
Шаблон страницы получил объект юзера - user._id user.name user.age и т.д. Всего и делов - спасибо ТиДжею Каравайчуку (или как там его) за Express.

вторник, 23 октября 2018 г.

Как обновить несколько элементов в массиве?

Необходимо обновить одним запросом несколько данных. Вот пример запроса:
db.coll.update( { article: 100500 }, { $set: { a: 555 }, $pull: { arr: { t: { $lt: 20 } } } } );
А вот пример самого документа:
{ article: 100500, a: 400, arr: [ { t: 30, b: 12, n: 90 }, { t: 10, b: 16, n: 60 } ] }
Мой запрос:
Обновляет значение a на 555 Удаляет все элементы массива arr, где t < 20
Суть вопроса: Надо обновить значения b в маccве arr. То есть, везде где n == 90, значение b надо поменять на 777. Как можно дополнить этот запрос, чтобы "убить сразу 3-х зайцев"?
В итоге должен получиться такой документ:
{ article: 100500, a: 555, /* Тут было: 400 */ arr: [ { t: 30, b: 777, n: 90 }, /* Тут был элемент массива */ ] }


Ответ

Я полагаю, у вас есть следующие документы в вашей коллекции.
{ "_id" : ObjectId("56b71025973d202a52a5e650"), "article" : 100500, "a" : 400, "arr" : [ { "t" : 30, "b" : 12, "n" : 90 }, { "t" : 20, "b" : 16, "n" : 60 } ] }, { "_id" : ObjectId("56b7102b973d202a52a5e651"), "article" : 100500, "a" : 400, "arr" : [ { "t" : 0, "b" : 12, "n" : 90 }, { "t" : 10, "b" : 16, "n" : 60 } ] }, { "_id" : ObjectId("56b710d4973d202a52a5e652"), "article" : 100500, "a" : 400, "arr" : [ { "t" : 30, "b" : 12, "n" : 90 }, { "t" : 27, "b" : 16, "n" : 32 } ] }

Прежде всего вы должны знать, что это не возможно, чтобы обновить более одного элемента в массиве используя метод update() даже с опцей multi: true или используя метод updateMany(); и все логики позади, что вы пытаетесь сделать; делать вещи более сложнее.
Лучший способ это делать это используя Bulk Операции
Решение для MongoDB версия 3.2 или новее:
MongoDB 3.2 не рекомендуется Bulk() и связанные с ним методы. Нужно использовать метод .bulkWrite()
Здесь у нас есть два варианта:
Нужно использовать агрегация чтотбы уменшать количество докуменьов которые нужно обновить. здесь в цепочке нужно только один этап: $project где мы используем оператор $filter
let requests = [];
db.collection.aggregate([ { "$project": { "deleteElements": { "$filter": { "input": "$arr", "as": "del", "cond": { "$lt": [ "$$del.t", 12 ] } } }, "updateElements": { "$filter": { "input": "$arr", "as": "upd", "cond": { "$and": [ { "$gte": [ "$$upd.t", 12 ] }, { "$eq": [ "$$upd.n", 90 ] } ] } } } }} ]).forEach(function(document) { document.deleteElements.forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.t": element.t }, "update": { "$pull": { "arr": element } } } } ); }); document.updateElements.forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.t": element.n }, "update": { "$set": { "arr.$.b": 777 } } } } ); }); requests.push( { "updateOne": { "filter": { "_id": document._id }, "update": { "$set": { "a": 555 } } } } ); })
db.collection.bulkWrite(requests) Используя метод .find()
db.collection.find({"article": 100500}).snapshot().forEach(function(document) { document.arr.filter(function(arr) { return arr.t < 12; }).forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.t": { "$lt": 12 }}, "update": { "$pull": { "arr": element } } } } ); }); document.arr.filter(function(arr) { return arr.n === 90; }).forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.n": 90 }, "update": { "$set": { "arr.$.b": 777 } } } } ); }); requests.push( { "updateOne": { "filter": { "_id": document._id }, "update": { "$set": { "a": 555 } } } } ); })
db.collection.bulkWrite(requests);

Решение для MongoDB версии 2.6 или новее:
var bulk = db.collection.initializeOrderedBulkOp(); var count = 0; db.collection.find({"article": 100500}).snapshot().forEach(function(document) { document.arr.filter(function(arr) { return arr.t < 12; }).forEach(function(element) { bulk.find({ "_id": document._id, "arr.t": { "$lt": 12 } } ).updateOne({ "$pull": { "arr": element } }); count++; }); document.arr.filter(function(arr) { return arr.n === 90; }).forEach(function(element) { bulk.find({ "_id": document._id, "arr.n": 90 }).updateOne({ "$set": { "arr.$.b": 777 } }); count++; }); bulk.find( { "_id": document._id } ).updateOne( { "$set": { "a": 555 } } ); count++; if (count % 1000 === 0) { // Выпольнить после 1000 операции bulk.execute(); bulk = db.collection.initializeOrderedBulkOp(); } })
// Очистить очереди if (count > 0) { bulk.execute(); }

Результать
{ "_id" : ObjectId("56b71025973d202a52a5e650"), "article" : 100500, "a" : 555, "arr" : [ { "t" : 30, "b" : 777, "n" : 90 }, { "t" : 20, "b" : 16, "n" : 60 } ] } { "_id" : ObjectId("56b7102b973d202a52a5e651"), "article" : 100500, "a" : 555, "arr" : [ ] } { "_id" : ObjectId("56b710d4973d202a52a5e652"), "article" : 100500, "a" : 555, "arr" : [ { "t" : 30, "b" : 777, "n" : 90 }, { "t" : 27, "b" : 16, "n" : 32 } ] }