How to use $in operator with pair of attributes - mongodb

Consider this collection
/* 1 */
{
"key" : 1,
"b" : 2,
"c" : 3
}
/* 2 */
{
"key" : 2,
"b" : 5,
"c" : 4
}
/* 3 */
{
"key" : 3,
"b" : 7,
"c" : 9
}
/* 4 */
{
"key" : 4,
"b" : 7,
"c" : 4
}
/* 5 */
{
"key" : 5,
"b" : 2,
"c" : 9
}
I want to use the $in operator and write a query to return the document such (b, c) IN ((2, 3), (7, 9)). It means "return all rows where b is 2 and c is 3 at the same time, OR b is 7 and с is 9 at the same time."
How can I use $in operator to use multiple attribute values.
If I use the following query
db.getCollection('test').find({
$and:[
{b:{$in:[2,7]}},
{c:{$in:[3,9]}}
]
})
then I get following results
(2,3)
(7,9)
(2,9) --> This is unwanted record.
IN SQL world it is possible
SELECT *
FROM demo
WHERE (b, c) IN ((2, 3), (7, 9))
What is the equivalent in Mongo DB?

If I get it right, the thing you are doing is getting all the pairs (2,3),(2,9),(7,3),(7,9).
But you want to match those one by one, so your valid pairs should be (2, 3), (7, 9). To satisfy this, you can match b and c one by one, pair them and "or" them after.
db.getCollection('test').find({
$or: [
{$and: [ {b : 2}, {c : 3} ]},
{$and: [ {b : 7}, {c : 9} ]}
]
})

Related

Mongo-graphql: query for two integer fields order by both fields and returns two rows if both fields have values

I have a document with entry_height, exit_height (might be null).
Height is a bitcoin thing (block height). Several entries can have the same entry_height or exit_height.
I want to show a list where there is a row for entry_height and, if exit_height is filled, also show a 2nd row.
I need to order by height of both fields.
Let's say I have these entries:
1) entry_height: 1, exit_height: 5, entry_data, exit_data, ...
2) entry_height: 2, exit_height: 3, entry_data, exit_data, ...
3) entry_height: 4, exit_height: null, entry_data, null
The query result would be:
1) height: 1, entry related data...
2) height: 2, entry related data...
3) height: 3, exit related data ...
4) height: 4, entry related data...
5) height: 5, exit related data...
What indices should be set and how to read the data from the database?
Thanks.
update: after some reading I think that entry_height and exit_height should be a unique array field, say, height: [1, 5], [2, 3], [4].
That way I'd set up a multikey index. But I'm not sure how to know if a value comes from the 1st height entry or the seond.
Regarding the query I think the only option is the aggregate framework.
What do you say?
This seems to do the trick:
var r = [
{_id:0, "entry_height":1, "exit_height":5, "entry_data":"entry_DAT1", "exit_data":"exit_DAT1"},
{_id:1, "entry_height":2, "exit_height":3, "entry_data":"entry_DAT2", "exit_data":"exit_DAT2"},
{_id:2, "entry_height":4, "entry_data":"entry_DAT3"}
];
db.foo.insert(r);
c = db.foo.aggregate([
// The Juice! "Array-ify" the doc and assign height and payload to common field names (h and d):
{$project: {x:[ {h:"$entry_height",d:"$entry_data",t:"ENTRY"}, {h:"$exit_height",d:"$exit_data",t:"EXIT"} ] }}
// The unwind creates 2 docs (in this case) for each input item
,{$unwind: "$x"}
// Toss out those items with no exit height (like _id = 2 above):
,{$match: {"x.h": {$exists: true} }}
// Finally: The sort you seek:
,{$sort: {"x.h":1}}
]);
{ "_id" : 0, "x" : { "h" : 1, "d" : "entry_DAT1", "t" : "ENTRY" } }
{ "_id" : 1, "x" : { "h" : 2, "d" : "entry_DAT2", "t" : "ENTRY" } }
{ "_id" : 1, "x" : { "h" : 3, "d" : "exit_DAT2", "t" : "EXIT" } }
{ "_id" : 2, "x" : { "h" : 4, "d" : "entry_DAT3", "t" : "ENTRY" } }
{ "_id" : 0, "x" : { "h" : 5, "d" : "exit_DAT1", "t" : "EXIT" } }
The heights are in order and you can use the t field to figure out if the d field is entry or exit data. If you have other ways of sniffing into the data then perhaps you do not need the t field.
With respect to indexing, not sure what you want to index to reduce the lookup space at the top of the aggregation pipeline.

importing objects into mongodb collection that are not duplicates that have had their _id removed

I have a .json file that I created using using mongoexport and then I removed the _id elements from the objects. I would like to take this json file and then import it into another collection using mongoimport, but I want to skip over any of the objects that are duplicates of anything already in the collection (minus the _id tag since it no longer exists in the data being imported). Is there a way to do this?
No. You would have to write some kind of script in the Mongo shell or program that would go through and manually compare the items.
one can crate an unique index on all key fields on target collection then use regular mongoimport, it will automatically ignore the duplication for you.
in example: imp collection contains 2 documents
>db.imp.find()
{ "_id" : ObjectId("559eb4d112bc601a37ba6c0e"), "a" : 1, "b" : 1, "c" : 1, "d" : "first" }
{ "_id" : ObjectId("559eb4e512bc601a37ba6c0f"), "a" : 2, "b" : 2, "c" : 2, "d" : "second" }
a,b and c are key fields, create an unique index on those fields
> db.imp.ensureIndex({a:1,b:1,c:1},{unique:true})
json file (imp.json) duplicate with existing (first two) records + another duplicate on a:3,b:3 and c:3
{ "a" : 1, "b" : 1, "c" : 1, "d" : "one" }
{ "a" : 2, "b" : 2, "c" : 2, "d" : "two"}
{ "a" : 3, "b" : 3, "c" : 3, "d" : "third"}
{ "a" : 3, "b" : 3, "c" : 3, "d" : "three"}
mongoimport, on mongo 3.0 you can use --maintainInsertionOrder to inserts the documents in the order of their appearance in the input source
$ mongoimport -d imp -c imp --file imp.json
import result and duplicate key error on index
connected to: 127.0.0.1
2015-07-10T01:14:40.457+0700 insertDocument :: caused by :: 11000 E11000 duplicate key error index: imp.imp.$a_1_b_1_c_1 dup key: { : 1, : 1, : 1 }
2015-07-10T01:14:40.458+0700 insertDocument :: caused by :: 11000 E11000 duplicate key error index: imp.imp.$a_1_b_1_c_1 dup key: { : 2, : 2, : 2 }
2015-07-10T01:14:40.458+0700 insertDocument :: caused by :: 11000 E11000 duplicate key error index: imp.imp.$a_1_b_1_c_1 dup key: { : 3, : 3, : 3 }
2015-07-10T01:14:40.459+0700 imported 4 objects
finally the imp collection will look like
> db.imp.find()
{ "_id" : ObjectId("559eb4d112bc601a37ba6c0e"), "a" : 1, "b" : 1, "c" : 1, "d" : "first" }
{ "_id" : ObjectId("559eb4e512bc601a37ba6c0f"), "a" : 2, "b" : 2, "c" : 2, "d" : "second" }
{ "_id" : ObjectId("559eba10394aeed912d00d31"), "a" : 3, "b" : 3, "c" : 3, "d" : "third" }
Hope this help!

MongoDB, how to use document as the smallest unit to search the document in array?

Sorry for the title, but I really do not know how to make it clear. But I can show you.
Here I have insert two document
> db.test.find().pretty()
{
"_id" : ObjectId("557faa461ec825d473b21422"),
"c" : [
{
"a" : 3,
"b" : 7
}
]
}
{
"_id" : ObjectId("557faa4c1ec825d473b21423"),
"c" : [
{
"a" : 1,
"b" : 3
},
{
"a" : 5,
"b" : 9
}
]
}
>
I only want to select the first document with a value which is greater than 'a' and smaller than 'b', like '4'.
But when i search, i cannot get the result i want
> db.test.find({'c.a': {$lte: 4}, 'c.b': {$gte: 4}})
{ "_id" : ObjectId("557faa461ec825d473b21422"), "c" : [ { "a" : 3, "b" : 7 } ] }
{ "_id" : ObjectId("557faa4c1ec825d473b21423"), "c" : [ { "a" : 1, "b" : 3 }, { "a" : 5, "b" : 9 } ] }
>
Because '4' is greater than the '"a" : 1' and smaller than '"b" : 9' in the second document even it is not in the same document in the array, so the second one selected.
But I only want the first one selected.
I found this http://docs.mongodb.org/manual/reference/operator/query/elemMatch/#op._S_elemMatch, but it seems the example is not suitable for my situation.
You would want to
db.test.findOne({ c: {$elemMatch: {a: {$lte: 4}, b: {$gte: 4} } } })
With your query, you are searching for documents that have an object in the 'c' array that has a key 'a' with a value <= 4, and a key 'b' with a value >= 4.
The second record is return because c[0].a is <= 4, and c[1].b is >= 4.
Since you specified you wanted to select only the first document, you would want to do a findOne() instead of a find().
Use $elemMatch as below :
db.test.find({"c":{"$elemMatch":{"a":{"$lte":4},"b":{"$gte":4}}}})
Or
db.test.find({"c":{"$elemMatch":{"a":{"$lte":4},"b":{"$gte":4}}}},{"c.$":1})

Is MongoDB field ordering behaviour different on _id and other fields?

I have recently encountered a bug in my server and after investigation it happens that MongoDB dictionaries are ordered because of BSON structure.
I thought I understood, but here is a test that I don't understand (mongo 2.6.4) : is it that field ordering matters only for _id ?
Test 1 : insert {a: 1, b: 2} and lookup {b: 2, a: 1} -> FOUND
> db.d.insert({a: 1, b: 2})
> db.d.find()
{ "_id" : ObjectId("54c4dfd17e8b0ba11cf1539d"), "a" : 1, "b" : 2 }
> db.d.find({b: 2, a: 1})
{ "_id" : ObjectId("54c4dfd17e8b0ba11cf1539d"), "a" : 1, "b" : 2 }
Test 2 : insert {smthg: {a: 1, b: 2}} and lookup {smthg: {b: 2, a: 1}} -> NOT FOUND
> db.d.insert({smthg: {a: 1, b: 2}})
> db.d.find({smthg: {b: 2, a: 1}})
> db.d.find({smthg: {a: 1, b: 2}})
{ "smthg" : { "a" : 1, "b" : 2 } }
Thanks for the explanation
I'll quote the docs directly on this:
Equality matches within subdocuments select documents if the
subdocument matches exactly the specified subdocument, including the
field order.
For that purpose, you will be better served using the dot notation:
db.d.find({"smthg.a" : 1, "smthg.b" : 2});

Mongo: Array field has no values in given array?

I'm trying to write up a mongo query that finds all entries where the "steps" field has no values within an array argument.
So for example, given two entries with values:
Entry1:
steps: [3, 4]
Entry2:
steps: [3, 5]
The query should return entry1, but not entry 2, for input array [4, 8, 10]. I'm quite new to mongo - any ideas appreciated.
You mean you have some records:
db.foo.find()
{ "_id" : 1, "steps" : [ 3, 4 ] }
{ "_id" : 2, "steps" : [ 3, 5 ] }
Then you would query:
> db.foo.find({steps:{$in:[4,8,10]}})
{ "_id" : 1, "steps" : [ 3, 4 ] }
the $in clause will pick records in which any stored element matches any of terms in the array supplied in the query