Sign up ×
Database Administrators Stack Exchange is a question and answer site for database professionals who wish to improve their database skills and learn from others in the community. It's 100% free, no registration required.

I have the following document in a mongodb collection which represents a Snort rule parsed with the perl Parse::Snort library:

{
"_id" : ObjectId("5328b974be4ed1400900000a"),
"dst_port" : "6000",
"opts" : [ 
    [ 
        "msg", 
        "\"X11 xopen\""
    ], 
    [ 
        "flow", 
        "established"
    ], 
    [ 
        "content", 
        "\"l|00 0B 00 00 00 00 00 00 00 00 00|\""
    ], 
    [ 
        "fast_pattern", 
        "only"
    ], 
    [ 
        "metadata", 
        "ruleset community"
    ], 
    [ 
        "classtype", 
        "unknown"
    ], 
    [ 
        "sid", 
        "1226"
    ], 
    [ 
        "rev", 
        "10"
    ], 
    [ 
        "gid", 
        "1"
    ]
],
"proto" : "tcp",
"direction" : "->",
"src" : "$EXTERNAL_NET",
"update" : "0",
"action" : "alert",
"dst" : "$HOME_NET",
"src_port" : "any"
}

I am trying to search all documents in this collection with opts.sid=1226,opts.gid=1 and opts.rev=10.

With the following line I am able to find all documents with sid=1226:

db.rules.find({"opts":{"$elemMatch":{"$all":["sid","1226"]}}});

But I can't figure out how to search filtering more fields such as ["gid","1"] and ["rev","10"]
Does anyone know how I can add the extra conditions?

share

migration rejected from serverfault.com Mar 22 '14 at 19:24

This question came from our site for system and network administrators. Votes, comments, and answers are locked due to the question being closed here, but it may be eligible for editing and reopening on the site where it originated.

closed as off-topic by Jack Douglas Mar 22 '14 at 19:24

If this question can be reworded to fit the rules in the help center, please edit the question.

    
This question appears to be off-topic because it is about programming in Perl –  Jack Douglas Mar 22 '14 at 19:24

1 Answer 1

You could possibly do this using $and, albeit in quite a messy way:

db.rules.find({ "$and": [
    {"opts":{"$elemMatch":{"$all":["sid","1226"]}}},
    {"opts":{"$elemMatch":{"$all":["gid","1"]}}},
    {"opts":{"$elemMatch":{"$all":["rev","10"]}}},
]})

That is untested, but may work. The real problem here is the nested arrays, and that each "option" set is in it's own array.

To do this better, the n you need to change the output from the Parse::Snort module to writing the options as one straight hash, but putting that into an array. Inserted using the MongoDB driver, the result should look like this:

{
    "_id" : ObjectId("5328b974be4ed1400900000a"),
    "dst_port" : "6000",
    "opts" : [{ 
        "msg": "\"X11 xopen\"", 
        "flow": "established", 
        "content": "\"l|00 0B 00 00 00 00 00 00 00 00 00|\"", 
        "fast_pattern": "only", 
        "metadata": "ruleset community", 
        "classtype": "unknown", 
        "sid": "1226", 
        "rev": "10", 
        "gid": "1"
    }],
    "proto" : "tcp",
    "direction" : "->",
    "src" : "$EXTERNAL_NET",
    "update" : "0",
    "action" : "alert",
    "dst" : "$HOME_NET",
    "src_port" : "any"
}

So the producing code is the problem ans should have probably looked something like this:

use Parse::Snort;
use MongoDB;
use Tie::IxHash;

my $client = MongoDB::MongoClient->new( host => 'yourhost' );
my $db = $client->get_database("yourdb");
my $collection = $db->get_collection("yourCollection");

# Then looping for each snort rule

my $rule = Parse::Snort->new();
$rule->parse("snortRule");

my $ruleObj = {};
tie %{$ruleObj}, 'Tie::IxHash';

foreach my $key (qw/ proto direction src update action dst src_port /) {
    $ruleObj->{$key} = $rule->$key if (defined $rule->$key);
}

if ( length(@{$rule->opts}) != 0 ) [

    my $opts = {};
    tie %{$opts}, 'Tie::IxHash';

    foreach my $opt ( $rule->opts ) {
        $opts->{ $opt[0] } = $opt[1];            
    }

    $ruleObj->{opts} = [$opts];
}

$collection->insert( $ruleObj );

And that will store the records correctly as shown above.

Then you can query for your matching document like this:

db.collection.find(
    { "opts": {"$elemMatch": { "sid": "1226", "gid": "0", "rev": "10" } } }
)

Which is a nicer way to look at it.

share
    
I rejected the migration: SF might now send it to SO and you may want to re-post your answer there if they do? –  Jack Douglas Mar 22 '14 at 19:26