LINUX.ORG.RU

Правильное проектирование mongodb, какой способ выбрать?

 


0

1

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

10.124.125.34 d4ca6d446af8 1 50
10.124.125.34 d4ca6d777b75 1 50
10.124.125.34 00179a0268d7 2 44
10.124.125.34 001f29ead868 2 50
10.124.125.34 0022640720e4 2 50
10.124.125.34 1cbdb98ed8d1 2 50
10.124.125.34 404a0377d3ac 2 46
10.124.125.34 5067f0179dbf 2 46
10.124.125.34 d4ca6d3315da 2 50
10.124.125.34 d4ca6d331601 2 50
10.124.125.34 d4ca6d33160e 2 50
10.124.125.34 00030d915586 100 50
10.124.125.34 000d8758e0ab 100 50

т.е. если разделить строку пробелами - то параметры будут такими: 1 - ip-адрес свитча; 2 - мак-адрес на порту; 3 - vlan; 4 - порт

Посчитал, что если хранить это дело в монго - то лучше будет хранить следующим образом:

{
ip: 'ip',
ports:[
    {
        name: 'portname',
        macvlan:[
            {
                mac: 'mac',
                vlan: 'vlan'
            }
        ]
    }
]
}

Закинул весь текстовый документ в бд по такому принципу и тут же напоролся на подводные камни.

Т.е. если я хочу узнать на каких свитчах был нужный мне мак - то это решается легко и просто таким запросом:

.find({'ports.macvlan.mac'}, {ip:1})

Но как в таком случае мне найти на каком именно порту сидит мак? Ведь запрос без «проекции» выдаст весь документ целиком, а как бы выглядел нужный мне запрос я найти пока не могу не могу (роюсь сейчас в документации)

Т.е. Нужно разбивать по разным коллекциям свитчи и порты и в коллекциях портов хранить id-шники свитчей?

Или не париться и хранить в денормализованном виде каждую строку текстовика таким образом:

{
ip:'',
mac:'',
vlan: '',
port: ''
}

Вобщем-то тоже работает шустро, учитывая, что затея не запланирована на особое количество данных и их долгое хранение.

★★★★★

Последнее исправление: Siado (всего исправлений: 1)

Я бы сделал так:

{
  "ip": "1.2.3.4",
   dat: [
     {
       mac: 'FF:00:FF:00:11:22',
       port: 1,
       vlan: 2
     },
     {
       mac: 'FF:00:FF:11:33:44',
       port: 3,
       vlan: 5
     }
   ]
}
Потому что поиск ip + mac|port|vlan возможен только в таком случае:
db.col.find({ip:"1.2.3.4","dat.mac":"FF:00:FF:00:11:22"})

gh0stwizard ★★★★★
()
Последнее исправление: gh0stwizard (всего исправлений: 1)

Но как в таком случае мне найти на каком именно порту сидит мак? Ведь запрос без «проекции» выдаст весь документ целиком, а как бы выглядел нужный мне запрос я найти пока не могу не могу (роюсь сейчас в документации)

Модель №1:

db.devices.find()
{ _id:1, sn: "sn0001", addr:["1.2.3.4","127.0.0.1"]}
{ _id:2, sn: "sn0002", addr:["10.0.0.1"]}

db.ports.find()
{ _id:1, device: ObjectId(1), mac: "11:22:33:44:55:66", vlan: 4, port: 1}
{ _id:2, device: ObjectId(2), mac: "33:33:33:55:55:66", vlan: 5, port: 3}

Модель №2 выше в моем примере.

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

Плюсы 2 модели - простота и атомарность документа.

gh0stwizard ★★★★★
()

Ведь запрос без «проекции» выдаст весь документ целиком, а как бы выглядел нужный мне запрос я найти пока не могу не могу (роюсь сейчас в документации)

Срез до первого попавшегося поля: http://docs.mongodb.org/manual/reference/projection/positional/#proj._S_

Только это не поможет, если ты хочешь чтобы было более чем одно совпадение.

db.col.find({"dat.vlan":5}, {"dat.$":1})
gh0stwizard ★★★★★
()
Последнее исправление: gh0stwizard (всего исправлений: 1)
Ответ на: комментарий от gh0stwizard

Да, сделал по этому способу. Только вот чтобы получить ссылку не на документ, а на конкретный массив запросы делаю так:

db.maclist.find({'dat.mac':'90f652410d6b'}, {'ip':1, 'dat.$.mac':1})

Вот тогда оно мне выдает аккуратненкий результат:

{ "_id" : ObjectId("5227a01ee13823298b82803e"), "dat" : [ { "mac" : "90f652410d6b", "vlan" : "100", "port" : "5" } ], "ip" : "10.124.125.35" }
{ "_id" : ObjectId("5227a01fe13823298b828057"), "dat" : [ { "mac" : "90f652410d6b", "vlan" : "100", "port" : "19" } ], "ip" : "10.124.125.147" }
{ "_id" : ObjectId("5227a01fe13823298b828058"), "dat" : [ { "mac" : "90f652410d6b", "vlan" : "100", "port" : "25" } ], "ip" : "10.124.125.148" }
{ "_id" : ObjectId("5227a022e13823298b828088"), "dat" : [ { "mac" : "90f652410d6b", "vlan" : "100", "port" : "Gi1/0/28" } ], "ip" : "10.124.125.224" }

Без $ лепит весь массив целиком. К стати, когда пробовал в своем первом случае делать что-то типа {'ports.$.macvlan.$.mac'} то выдавало ошибку.

Siado ★★★★★
() автор топика
Ответ на: комментарий от vden

Просто ради интереса: а чем не подошла для этой задачи обычная RDBMS?

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

Siado ★★★★★
() автор топика
Ответ на: комментарий от gh0stwizard

Только это не поможет, если ты хочешь чтобы было более чем одно совпадение.

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

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

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

Siado ★★★★★
() автор топика
Последнее исправление: Siado (всего исправлений: 1)
Ответ на: комментарий от Siado

Монга оперирует на уровне документа. Все суб/под это костыли в моем понимании. Потому что проектировать надо с учетом запросов в отличие от СУБД, где педалит иерархия. Задачи в сабже ты решил, но я же не телепат :)

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

gh0stwizard ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.