MongoDB reference in validation schema - mongodb

Is there a way in mongodb to reference an element to another in the same document in schema validation? In JSON schema $ref is not supported so what's the alternative? Is there any workaround? Thank anyone for help. Here is an example:
{
a : [1, 4, 9, 10]
b : 1
}
In this case, what we want is to ensure that the value of "b" is in the array "a" in order not to have something like { b : 5 },
which value 5 is not in the "a" array. Thank anyone for help

can't you map through a and check if b equals an index of a else error

Related

How to do multiple where query without effect data in TypeORM?

I want to do multiple where query without effect data. I want to get data that include at least 1 data per array. Pseudo code
data =[1,3]
array1 = [1,2]
array2 = [3,4]
if(data.IsIntersect(array1) and data.IsIntersect(array2))
IsIntersect checks are there a intersection beetween arrays
I did so far
queryBuilder.andWhere(
'properties.id IN (:...sizeIds) AND properties.id IN (:...colorIds)',
{ sizeIds: [1, 2], colorIds: [3, 4] },
);
It returns empty because firstly checks properties for 'sizeIds' then it checks for 'colorIds'. For example
properties includes 1,3
check for sizeIds, returns 1
check for colorIds, return empty
How can I do that with typeORM?
How can properties.id be 1 and 3? And if it is, how could 1 or 3 be in both? You're asking for the impossible.
I assume you mean to ask for when properties.id is 1 or 3, because if it is [1,3] then you should use the postgres array syntax {1,3} & the ANY keyword (some variation on this: Check if value exists in Postgres array).
tldr, I think all you need is brackets and OR instead of AND:
queryBuilder.andWhere(
'(properties.id IN (:...sizeIds) OR properties.id IN (:...colorIds))',
{ sizeIds: [1, 2], colorIds: [3, 4] },
);
If properties.id is in fact an array, then please add the entity definition to your question. If you want to merge the rows where properties.id is in the list you will need a GROUP BY (https://orkhan.gitbook.io/typeorm/docs/select-query-builder).

What does $sum:1 mean in Mongo

I have a collection foo:
{ "_id" : ObjectId("5837199bcabfd020514c0bae"), "x" : 1 }
{ "_id" : ObjectId("583719a1cabfd020514c0baf"), "x" : 3 }
{ "_id" : ObjectId("583719a6cabfd020514c0bb0") }
I use this query:
db.foo.aggregate({$group:{_id:1, avg:{$avg:"$x"}, sum:{$sum:1}}})
Then I get a result:
{ "_id" : 1, "avg" : 2, "sum" : 3 }
What does {$sum:1} mean in this query?
From the official docs:
When used in the $group stage, $sum has the following syntax and returns the collective sum of all the numeric values that result from applying a specified expression to each document in a group of documents that share the same group by key:
{ $sum: < expression > }
Since in your example the expression is 1, it will aggregate a value of one for each document in the group, thus yielding the total number of documents per group.
Basically it will add up the value of expression for each row. In this case since the number of rows is 3 so it will be 1+1+1 =3 . For more details please check mongodb documentation https://docs.mongodb.com/v3.2/reference/operator/aggregation/sum/
For example if the query was:
db.foo.aggregate({$group:{_id:1, avg:{$avg:"$x"}, sum:{$sum:$x}}})
then the sum value would be 1+3=4
I'm not sure what MongoDB version was there 6 years ago or whether it had all these goodies, but it seems to stand to reason that {$sum:1} is nothing but a hack for {$count:{}}.
In fact, $sum here is more expensive than $count, as it is being performed as an extra, whereas $count is closer to the engine. And even if you don't give much stock to performance, think of why you're even asking: because that is a less-than-obvious hack.
My option would be:
db.foo.aggregate({$group:{_id:1, avg:{$avg:"$x"}, sum:{$count:{}}}})
I just tried this on Mongo 5.0.14 and it runs fine.
The good old "Just because you can, doesn't mean you should." is still a thing, no?

Mongo one attribute different than the other attribute [duplicate]

This question already has answers here:
Compare two date fields in MongoDB
(6 answers)
Closed 8 years ago.
How do I do a MongoDB find comparing two attribute of the same document?
Like, if I have the collection "test", with this structure:
{a : 3, b : 4}
{a : 5, b : 5}
{a : 6, b : 6}
and I want to find all documents where the attribute 'a' is different than the attribute 'b', which would be the entry
{a : 3, b : 4}
.
I thought this could be accomplised by:
db.test.find({a : { $ne : b}})
but it didn't work. It gives me
Fri Aug 1 13:54:47 ReferenceError: b is not defined (shell):1
If this is an ad-hoc query and you don't want to keep track of different attributes (as mentioned in the entry posted by Marc B., then you can simply go with:
db.test.find("this.a != this.b");
This is going to be slow, depending on how many entries you have.

How does MongoDB pick a first property it will sort by?

db.numbers.find().sort( { a : 1, b : 1, c : 1 })
If I execute this command MongoDB will sort numbers collection by property 'a', if 'a' is the same on two docs it will sort them by 'b' property, if that is the same too it will go on to 'c'. I hope I got that right, correct me if not.
But how does it pick 'a' property as first when it is just a JS object? Does it iterate over sorting object properties using for(var propr in ...) and whichever is first is also first to be sorted by?
Internally, MongoDB doesn't use JSON, is uses BSON. While JSON is technically un-ordered, BSON, (per the specification) is ordered. This is how MongoDB knows that in {a:1, b:1, c:1} that the keys are ordered "a,b,c": the underlying implementation is ordered as well.
As #Sammaye posted above in the comments, the JavaScript dictionary must be created with key priority in mind.
Hence, if you do something like this:
db.numbers.find().sort({
a: 1,
b: 1,
c: 1
});
your results will be sorted first by a, then by b, then by c.
If you do this, however:
db.numbers.find().sort({
c: 1,
a: 1,
b: 1
});
your results will be sorted first by c, then by a, then by b.
By using those keys you mentioned:
db.numbers.find().sort({
a: 1,
b: 1,
c: 1
});
MongoDB sorts with property a, b, and then c.
Basically, MongoDB scans from the beginning of the datafile (CMIIW). Hence, if MongoDB finds two or more documents with the same keys as yours (a,b, and c), it prints the first document found in the datafile first.

Mongo DB: how to select items with nested array count > 0

The database is near 5GB. I have documents like:
{
_id: ..
user: "a"
hobbies: [{
_id: ..
name: football
},
{
_id: ..
name: beer
}
...
]
}
I want to return users who have more then 0 "hobbies"
I've tried
db.collection.find({"hobbies" : { &gt : 0}}).limit(10)
and it takes all RAM and no result.
How to do conduct this select?
And how to return only: id, name, count ?
How to do it with c# official driver?
TIA
P.S.
near i've found:
"Add new field to hande category size. It's a usual practice in mongo world."
is this true?
In this specific case, you can use list indexing to solve your problem:
db.collection.find({"hobbies.0" : {$exists : true}}).limit(10)
This just makes sure a 0th element exists. You can do the same to make sure the list is shorter than n or between x and y in length by checking the existing of elements at the ends of the range.
Have you tried using hobbies.length. i haven't tested this, but i believe this is the right way to query the range of the array in mongodb
db.collection.find({$where: '(this.hobbies.length > 0)'})
You can (sort of) check for a range of array lengths with the $size operator using a logical $not:
db.collection.find({array: {$not: {$size: 0}}})
That's somewhat true.
According to the manual
http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24size
$size
The $size operator matches any array with the specified number of
elements. The following example would match the object {a:["foo"]},
since that array has just one element:
db.things.find( { a : { $size: 1 } } );
You cannot use $size to find a range of sizes (for example: arrays
with more than 1 element). If you need to query for a range, create an
extra size field that you increment when you add elements
So you can check for array size 0, but not for things like 'larger than 0'
Earlier questions explain how to handle the array count issue. Although in your case if ZERO really is the only value you want to test for, you could set the array to null when it's empty and set the option to not serialize it, then you can test for the existence of that field. Remember to test for null and to create the array when you want to add a hobby to a user.
For #2, provided you added the count field it's easy to select the fields you want back from the database and include the count field.
if you need to find only zero hobbies, and if the hobbies key is not set for someone with zero hobbies , use EXISTS flag.
Add an index on "hobbies" for performance enhancement :
db.collection.find( { hobbies : { $exists : true } } );
However, if the person with zero hobbies has empty array, and person with 1 hobby has an array with 1 element, then use this generic solution :
Maintain a variable called "hcount" ( hobby count), and always set it equal to size of hobbies array in any update.
Index on the field "hcount"
Then, you can do a query like :
db.collection.find( { hcount : 0 } ) // people with 0 hobbies
db.collection.find( { hcount : 5 } ) // people with 5 hobbies
3 - From #JohnPs answer, "$size" is also a good operator for this purpose.
http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24size