mongodb query multiple pairs using $in - sql

I have a collection names with data (_id is omitted):
{first:"John", last:"Smith"},
{first:"Alice", last:"Johnson"},
{first:"Bob", last:"Williams"},
...
and {first, last} is a unique index.
I want to find a lot of names in names like:
db.names.find({$or: [{first:"Alice", last:"Brown"}, {first:"Bob", last:"White"}, ...]}
Can I use $in instead of $or to simplify this query?
===
I know in MySQL this following query:
SELECT * FROM names WHERE (first = 'Alice' AND last = 'Brown') OR (first = 'Bob' AND last = 'White') OR ...
can be simplified as:
SELECT * FROM names WHERE (first, last) IN (('Alice', 'Brown'), ('Bob','White') OR ...)
But I am unable to find the equivalent query syntax in MongoDB.

The following query can get us the expected output:
db.names.find({
$expr:{
$in:[
{
"first":"$first",
"last":"$last"
},
[
{
"first" : "Alice",
"last" : "Johnson"
},
{
"first" : "Bob",
"last" : "Williams"
}
]
]
}
}).pretty()
Data set:
{
"_id" : ObjectId("5d81c3b7a832f81a9e02337b"),
"first" : "John",
"last" : "Smith"
}
{
"_id" : ObjectId("5d81c3b7a832f81a9e02337c"),
"first" : "Alice",
"last" : "Johnson"
}
{
"_id" : ObjectId("5d81c3b7a832f81a9e02337d"),
"first" : "Bob",
"last" : "Williams"
}
Output:
{
"_id" : ObjectId("5d81c3b7a832f81a9e02337c"),
"first" : "Alice",
"last" : "Johnson"
}
{
"_id" : ObjectId("5d81c3b7a832f81a9e02337d"),
"first" : "Bob",
"last" : "Williams"
}
Query Analysis: This query won't use the unique index you have created and I would recommend to go with the $or query.
Following are the winning plans:
$or query:
{
"stage" : "COLLSCAN",
"filter" : {
"$expr" : {
"$in" : [
{
"first" : "$first",
"last" : "$last"
},
{
"$const" : [
{
"first" : "Alice",
"last" : "Johnson"
},
{
"first" : "Bob",
"last" : "Williams"
}
]
}
]
}
},
"direction" : "forward"
}
$in query:
{
"stage" : "SUBPLAN",
"inputStage" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "OR",
"inputStages" : [
{
"stage" : "IXSCAN",
"keyPattern" : {
"first" : 1,
"last" : 1
},
"indexName" : "first_1_last_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"first" : [ ],
"last" : [ ]
},
"isUnique" : true,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"first" : [
"[\"Alice\", \"Alice\"]"
],
"last" : [
"[\"Brown\", \"Brown\"]"
]
}
},
{
"stage" : "IXSCAN",
"keyPattern" : {
"first" : 1,
"last" : 1
},
"indexName" : "first_1_last_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"first" : [ ],
"last" : [ ]
},
"isUnique" : true,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"first" : [
"[\"Bob\", \"Bob\"]"
],
"last" : [
"[\"White\", \"White\"]"
]
}
}
]
}
}
}
You can see that the index is properly utilized in $or query and not used in the $in query.

For this mysql query
SELECT * FROM names
WHERE (first = 'Alice' AND last = 'Brown')
OR (first = 'Bob' AND last = 'White')
OR ...
can be use in mongodb as
db.names.find({
$or: [
{ first: "Alice", last: "Brown" },
{ first: "Bob", last: "White" },
...
]})
For below mysql query
SELECT * FROM names
WHERE (first, last) IN (('Alice', 'Brown'), ('Bob','White') OR ...)
You can not create mongodb $in query
db.names.find({
$or: [
{ first: { $in: ["John", "Alice", "Bob"] } },
{ last: { $in: ["Smith", "Johnson", "Williams" ] } },
]})
Because it pass this result too
("John", "Johnson"),("John", "Williams"),("John", "Smith"),("John", "Williams")..
the best way is $or as ask in question
db.names.find({
$or: [
{ first: "Alice", last: "Brown" },
{ first: "Bob", last: "White" },
...
]})
May be better solution present out there. I will update my answer if find any. Thanks

Yes, it's possible to use $in to query MongoDb collections based on multiple values.
Try using the below syntax:
db.names.find.({ field: { $in: [<value1>, <value2>, ... <valueN> ] } })
for example in your case it looks like:
db.names.find({first: {$in: ["Alice","Brown","Bob", "White"]}})

Related

How do i change MongoDB JSON data to array

I need to update the MongoDB field with the array of objects where JSON object to be updated with as an array
if I have something like this in MongoDB
"designSectionContents" : [
{
"_id" : "5bae17ecbd7595540145ec98",
"type" : "subSection",
"columns" : [
{
"0" : {
"itemId" : "5b7465980783d9a37058f160",
"type" : "field"
}
},
{
"0" : {
"itemId" : "5b7465630783d9a37058f15c",
"type" : "field"
}
},
{
"0" : {
"itemId" : "5b7465810783d9a37058f15e",
"type" : "field"
}
}
],
"subSectionContentLayout" : {
"labelPlacement" : "Top",
"columns" : 3
}
}
]
I want to change the above snippet to below in MongoDB
"designSectionContents" : [
{
"_id" : ObjectId("5bae17ecbd7595540145ec98"),
"type" : "subSection",
"columns" : [
[
{
"itemId" : "5b7465980783d9a37058f160",
"type" : "field"
}
],
[
{
"itemId" : "5b7465630783d9a37058f15c",
"type" : "field"
}
],
[
{
"itemId" : "5b7465810783d9a37058f15e",
"type" : "field"
}
]
]
}
]
curly braces opening and closing tag has to be changed to array
This should work:
db.collection.aggregate([
{
"$project": {
"designSectionContents": {
"$map": {
"input": "$designSectionContents",
"as": "designSectionContent",
"in": {
"_id": "$$designSectionContent._id",
"type": "$$designSectionContent.type",
"columns": {
"$map": {
"input": "$$designSectionContent.columns",
"as": "inp",
"in": [
"$$inp.0"
]
}
}
}
}
}
}
}
]);
Here's the working link.

How could I create indexes in postgres using jsonb?

I have a table in my database as follows
my_table:jsonb
[ {
"name" : "world map",
"type" : "activated",
"map" : [ {
"displayOrder" : 0,
"value" : 123
}, {
"displayOrder" : 1,
"value" : 456
}, {
"displayOrder" : 2,
"value" : 789
} ]
}, {
"name" : "regional map",
"type" : "disabled"
} ]
I would like to create indices for the name, type and displayOrder fields, which would be the best way?

db.find vs db.aggregation to select nested array Object

I'v tried to perform the following query :
db.getCollection('fxh').find({"username": "user1", "pf.acc.accnbr" : 915177},{userid: true, "pf.pfid": true, "pf.acc.accid":true})
and my collection is the following :
{
"_id" : ObjectId("5932fd8f381d4c0a7de21942"),
"userid" : 1496513894,
"username" : "user1",
"email" : "user1#gmail.com",
"fullname" : "User 1",
"pf" : {
"acc" : [
{
"cyc" : [
{
"det" : {
"status" : "New",
"dcycid" : 1496513941
},
"status" : "New",
"name" : "QPT202017_M1",
"cycid" : 1496513940
}
],
"status" : "New",
"accnbr" : 915177,
"accid" : 1496513939
},
{
"cyc" : [
{
"det" : {
"status" : "New",
"dcycid" : 1496552643
},
"status" : "New",
"name" : "QPT202017_S8",
"cycid" : 1496552642
}
],
"status" : "New",
"accnbr" : 73497,
"accid" : 1496552641
}
],
"pfid" : 1496513935,
},
"lastupdate" : ISODate("2017-06-03T18:18:55.080Z"),
"__v" : 0
}
When I execute the query the result is the following :
{
"_id" : ObjectId("5932fd8f381d4c0a7de21942"),
"userid" : 1496513894,
"portfolio" : {
"acc" : [
{
"accid" : 1496513939
},
{
"accid" : 1496552641
}
],
"pfid" : 1496513935
}
}
And my problem is that I need to see only the concerned accid and the result returns the all accid !.
Any idea how just to return the selected accid of accnbr ?
NB : I have also tried to add $ sign at the end of my query , it
selects the right acc but it returns the all objects or I need just
only ONE returned object.
On 6/5/17
I also used the aggregate command instead of find and it get result by using this :
db.getCollection('fxh').aggregate([ { $unwind : "$pf.acc"} , { $match : {"username":"adh1", "pf.acc.accbr": 915177 } }, {$project : {_id:0, accid: "$pf.acc.accid"}}])
But could NOT get a lower level result, when I ran this :
db.getCollection('fxh').aggregate([ { $unwind : "$pf.acc.cyc"} , { $match : {"username":"adh1", "pf.acc.accbr": 915177, "pf.acc.cyc.name": "QPT202017_M1" } }, {$project : {_id:0, cycid: "$pf.acc.cyc.cycid"}}])
Any idea ?
You can try the below aggregation pipeline.
The idea is to $unwind one nested level at a time, starting from the outermost to the innermost.
For each nested level unwinding, you can apply the$match to limit the documents and continue till you have the desired shape.
You can $group it together at the end to get back to the original shape.
db.getCollection('fxh').aggregate([
{ $match : {"username":"adh1"} },
{ $unwind : "$pf.acc"} ,
{ $match : {"pf.acc.accbr": 915177 } },
{ $unwind : "$pf.acc.cyc"},
{ $match : {"pf.acc.cyc.name": "QPT202017_M1" } },
{$project : {_id:0, accid: "$pf.acc.accid", cycid: "$pf.acc.cyc.cycid"}}])

Scoring documents in Lucene 6.2.0

My query in lucene 6.2.0 goes like:
query query = new PhraseQuery.Builder()
.add(new Term("country","russia"))
.setSlop(1)
.build();
Basically among all my documents which are:
{
"_id" : ObjectId("586b723b4b9a835db416fa26"),
"name" : "test",
"countries" : {
"country" : [
{
"name" : "russia"
},
{
"name" : "USA china"
}
]
}
}
{
"_id" : ObjectId("586b73f24b9a835fefb10ca5"),
"name" : "nitika jain",
"countries" : {
"country" : [
{
"name" : "russia and denmrk"
},
{
"name" : "USA china"
}
]
}
}
{
"_id" : ObjectId("586b744f4b9a835fefb10ca7"),
"name" : "arjun",
"countries" : {
"country" : [
{
"name" : "russia pakistan"
},
{
"name" : "india iraq"
}
]
}
}
I want a document which has only russia. Ideally it should be the one highest scored, but instead I get something like "Found 3 hits."
Document<stored,indexed,tokenized<id:586b723b4b9a835db416fa26> stored,indexed,tokenized,omitNorms,indexOptions=DOCS<name:test> stored,indexed,tokenized,omitNorms,indexOptions=DOCS<countries:{ "country" : [ { "name" : "russia"} , { "name" : "USA china"}]}> stored,indexed,tokenized<country:russia> stored,indexed,tokenized<country:USA china>>**0.12874341**
Document<stored,indexed,tokenized<id:586b73f24b9a835fefb10ca5> stored,indexed,tokenized,omitNorms,indexOptions=DOCS<name:nitika jain> stored,indexed,tokenized,omitNorms,indexOptions=DOCS<countries:{ "country" : [ { "name" : "russia and denmrk"} , { "name" : "USA china"}]}> stored,indexed,tokenized<country:russia and denmrk> stored,indexed,tokenized<country:USA china>>**0.12874341**
Document<stored,indexed,tokenized<id:586b744f4b9a835fefb10ca7> stored,indexed,tokenized,omitNorms,indexOptions=DOCS<name:arjun> stored,indexed,tokenized,omitNorms,indexOptions=DOCS<countries:{ "country" : [ { "name" : "russia pakistan"} , { "name" : "india iraq"}]}> stored,indexed,tokenized<country:russia pakistan> stored,indexed,tokenized<country:india iraq>>**0.12874341**
All 3 results are equally scored. How can I get the document with only russia to be highest scored?
In Phrase queries, the slop is zero by default, requiring exact matches. that means that if you modify your query in this way:
query query = new PhraseQuery.Builder()
.add(new Term("country","russia"))
.build();
you'll get what you're looking for.

How does MongoDB index arrays?

In MongoDB, if I were to store an array (say ["red", "blue"]) in a field "color", does it index "red" and "blue" so I could query for "red", for example, or does in make {"red", "blue"} a composite index?
When it comes to indexing arrays, MongoDB indexes each value of the array so you can query for individual items, such as "red." For example:
> db.col1.save({'colors': ['red','blue']})
> db.col1.ensureIndex({'colors':1})
> db.col1.find({'colors': 'red'})
{ "_id" : ObjectId("4ccc78f97cf9bdc2a2e54ee9"), "colors" : [ "red", "blue" ] }
> db.col1.find({'colors': 'blue'})
{ "_id" : ObjectId("4ccc78f97cf9bdc2a2e54ee9"), "colors" : [ "red", "blue" ] }
For more information, check out MongoDB's documentation on Multikeys: http://www.mongodb.org/display/DOCS/Multikeys
You can simply test index usage by appending "explain" to your query:
> db.col1.save({'colors': ['red','blue']})
# without index
> db.col1.find({'colors': 'red'}).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "protrain.col1",
"indexFilterSet" : false,
"parsedQuery" : {
"colors" : {
"$eq" : "red"
}
},
"winningPlan" : {
"stage" : "COLLSCAN", <--- simple column scan
"filter" : {
"colors" : {
"$eq" : "red"
}
},
"direction" : "forward"
},
"rejectedPlans" : [ ]
},
"serverInfo" : {
"host" : "bee34f15fe28",
"port" : 27017,
"version" : "3.4.4",
"gitVersion" : "888390515874a9debd1b6c5d36559ca86b44babd"
},
"ok" : 1
}
# query with index
> db.col1.createIndex( { "colors":1 } )
> db.col1.find({'colors': 'red'}).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "protrain.col1",
"indexFilterSet" : false,
"parsedQuery" : {
"colors" : {
"$eq" : "red"
}
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN", <!---- INDEX HAS BEEN USED
"keyPattern" : {
"colors" : 1
},
"indexName" : "colors_1",
"isMultiKey" : true,
"multiKeyPaths" : {
"colors" : [
"colors"
]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"colors" : [
"[\"red\", \"red\"]"
]
}
}
},
"rejectedPlans" : [ ]
},
"serverInfo" : {
"host" : "bee34f15fe28",
"port" : 27017,
"version" : "3.4.4",
"gitVersion" : "888390515874a9debd1b6c5d36559ca86b44babd"
},
"ok" : 1
}
For structures where you have structured indexes, you could use the array position to index fields inside arrays:
{
'_id': 'BB167E2D61909E848EBC96C7B33251AC',
'hist': {
'map': {
'10': 1
}
},
'wayPoints': [{
'bhf_name': 'Zinsgutstr.(Berlin)',
'ext_no': 900180542,
'lat': 52.435158,
'lon': 13.559086,
'puic': 86,
'time': {
'dateTime': '2018-01-10T09: 38: 00',
'offset': {
'totalSeconds': 3600
}
},
'train_name': 'Bus162'
},
{
'bhf_name': 'SAdlershof(Berlin)',
'ext_no': 900193002,
'lat': 52.435104,
'lon': 13.54055,
'puic': 86,
'time': {
'dateTime': '2018-01-10T09: 44: 00',
'offset': {
'totalSeconds': 3600
}
},
'train_name': 'Bus162'
}]
}
db.col.createIndex( { "wayPoints.0.ext_no":1 } )
db.col.createIndex( { "wayPoints.0.train_name":1 } )
db.col.createIndex( { "wayPoints.1.ext_no":1 } )
db.col.createIndex( { "wayPoints.1.train_name":1 } )
> db.col.find(
... {
... "wayPoints.ext_no": 900180542
... }
... ,
... {
... "wayPoints.ext_no":1,
... "wayPoints.train_name":1,
... "wayPoints.time":1
... }
... ).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "db.col",
"indexFilterSet" : false,
"parsedQuery" : {
"wayPoints.ext_no" : {
"$eq" : 900180542
}
},
"winningPlan" : {
"stage" : "PROJECTION",
"transformBy" : {
"wayPoints.ext_no" : 1,
"wayPoints.train_name" : 1,
"wayPoints.time" : 1
},
"inputStage" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"wayPoints.ext_no" : 1
},
"indexName" : "wayPoints.ext_no_1",
"isMultiKey" : true,
"multiKeyPaths" : {
"wayPoints.ext_no" : [
"wayPoints"
]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"wayPoints.ext_no" : [
"[900180542.0, 900180542.0]"
]
}
}
}
},
"rejectedPlans" : [ ]
},
"serverInfo" : {
"host" : "bee34f15fe28",
"port" : 27017,
"version" : "3.4.4",
"gitVersion" : "888390515874a9debd1b6c5d36559ca86b44babd"
},
"ok" : 1
}