Why did this mongoose search match these documents? - node.js

I was trying to figure out if one of my users had any data associated with a goal with code "2" (which would have meant a bug) so I searched mongoose for
Entry.find({userid: req.user._id, 'goalSummary.2': {$exists: true}})
The goalSummary property is of type mongoose.Schema.Types.Mixed with keys identical to the goal codes (as strings, if that matters) and objects as values.
I got back 16 results, which each had goalSummarys like this:
goalSummary: {
"1": {
outcomes: 1,
intendedcount: 1,
extrascount: 0,
notdonecount: 0,
enough: "e"
},
"3": {
outcomes: 1,
intendedcount: 1,
extrascount: 0,
notdonecount: 0,
enough: "e"
},
[...]
}
...ie no 2 key. Why could these have matched? Was 2 set to undefined but not deleted? It successfully didn't match hundreds of other entries.

"field.2" only makes sense in Array types of mongoose properties. For Mixed, mongoose doesn't know anything about your document, so it will match everything, as long as there is a value.
On a side note, being burned myself and seeing others repeating it, I can also advice you too not to use keys for naming stuff. Rather do something like { key: 1, value: {outcomes: 1 ... }}.

Related

Why am I unable to change values of a Mongoose object to a different type ‘directly’?

I've just spent a good hour figuring out something mind-boggling (at least to me, as a JS noob) and I'd like to understand the underlying logic (or just why it works this way, because I think it's illogical and quite unexpected).
Suppose I'm using Mongoose to retrieve documents from a database, some or all of which include a date property (created with new Date()), a numeric property, and a string property.
[{
string: 'foo',
date: '2018-10-13T21:11:39.244Z',
number: 10
},
...
{
string: 'bar',
date: '2018-10-13T21:12:39.244Z',
number: 20
}]
I thus obtain an array of objects and now want to take the date property for each object and change the value to a string, so I do something like:
doc.find({}, (err, list) => {
list.forEach((item, index) => {
list[index].date = 'new value'
})
})
But I can't do that!
I can do list[index].string = 'new value' as well as list[index].date = new Date() but I can't change values that are of a different type, in this example date and number.
However, when I do list[index]._doc.date = 'new value', which took so long to figure out because I didn't know Mongoose objects weren't just plain old objects and focused on solving problems I didn't have instead, I can modify the value just fine.
It appears that the mongoose object somehow translates obj.key to obj._doc.key only if the type of the value matches but I'd appreciate a more detailed explanation than my uneducated guesses.
I suppose you want to use multi type on a document field, Mongoose support this by "Mixed" type when you define the Schema.
You can get more detail from https://mongoosejs.com/docs/schematypes.html#mixed.

Couchdb - How get results in reversed order by date and without id field

I'm testing some Couchdb features and I want get results with a reversed order by insertion date, querying by "i" field
A sample doc:
{
"_id": "970c3a0fdbb23dde47fb4075091a4d2b",
"_rev": "1-54448147611ff5e89189bb44e58c1521",
"doc_type": "Test",
"e": "3/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/36/2",
"d": "64/183/329/2/360/10/13/47/6/351/331/320/355/342/7/335/47/18/30/56/18/323/351/325/323/218/163/155/155/155/155",
"f": "1399305161/1399305185/1399305194/1399305254/1399305314/1399305374/1399305434/1399305447/1399305506/1399305566/1399305626/1399305668/1399305727/1399305787/1399305847/1399305908/1399305963/1399305970/1399306022/1399306068/1399306078/1399306100/1399306159/1399306219/1399306279/1399306308/1399306321/1399306379/1399306439/1399306493/1399306506",
"i": "3566120224",
"dated": "1399305161",
"v": "0/5/6/32/63/63/51/16/35/60/0/10/64/31/64/48/14/31/6/55/60/50/0/0/21/5/34/0/0/0/0",
"date": "2014-05-05T15:52:42Z"
}
My view:
function(doc) {
if(doc.i && doc.date){
emit([doc.i,doc.date],1); // 1 to test only
}
}
I'm testing it with:
myview?startkey=["3566120224"]&endkey=["3566120224",{}]&reversed=true
But I'm getting the data with a date order not reversed
{"total_rows":545,"offset":508,"rows":[
{"id":"407ee687674b783601ce6d7da906515e","key":["3566120224","2014-05-05T14:11:01Z"],"value":1},
{"id":"407ee687674b783601ce6d7da9062b51","key":["3566120224","2014-05-05T14:15:21Z"],"value":1},
{"id":"407ee687674b783601ce6d7da905f4d9","key":["3566120224","2014-05-05T14:19:41Z"],"value":1},
{"id":"407ee687674b783601ce6d7da905b4e1","key":["3566120224","2014-05-05T14:24:01Z"],"value":1},
{"id":"407ee687674b783601ce6d7da905733c","key":["3566120224","2014-05-05T14:28:22Z"],"value":1},
{"id":"407ee687674b783601ce6d7da904e7ea","key":["3566120224","2014-05-05T14:32:42Z"],"value":1},
{"id":"407ee687674b783601ce6d7da9043709","key":["3566120224","2014-05-05T14:37:02Z"],"value":1},
{"id":"407ee687674b783601ce6d7da9039896","key":["3566120224","2014-05-05T14:41:22Z"],"value":1},
{"id":"407ee687674b783601ce6d7da90303be","key":["3566120224","2014-05-05T14:45:43Z"],"value":1},
{"id":"407ee687674b783601ce6d7da90239ae","key":["3566120224","2014-05-05T14:50:03Z"],"value":1},
{"id":"407ee687674b783601ce6d7da9018442","key":["3566120224","2014-05-05T14:54:23Z"],"value":1},
{"id":"407ee687674b783601ce6d7da90104f0","key":["3566120224","2014-05-05T14:58:43Z"],"value":1},
{"id":"407ee687674b783601ce6d7da9007b67","key":["3566120224","2014-05-05T15:03:04Z"],"value":1},
{"id":"90bb394f7a4a581ff4dc78bfaffff448","key":["3566120224","2014-05-05T15:07:24Z"],"value":1},
{"id":"90bb394f7a4a581ff4dc78bfafff368e","key":["3566120224","2014-05-05T15:11:44Z"],"value":1},
{"id":"90bb394f7a4a581ff4dc78bfaffe7e65","key":["3566120224","2014-05-05T15:16:05Z"],"value":1},
{"id":"970c3a0fdbb23dde47fb4075091f8e5c","key":["3566120224","2014-05-05T15:24:45Z"],"value":1},
{"id":"970c3a0fdbb23dde47fb4075091f6241","key":["3566120224","2014-05-05T15:29:05Z"],"value":1},
{"id":"970c3a0fdbb23dde47fb4075091f254a","key":["3566120224","2014-05-05T15:33:26Z"],"value":1},
{"id":"970c3a0fdbb23dde47fb4075091ed01b","key":["3566120224","2014-05-05T15:37:46Z"],"value":1},
{"id":"970c3a0fdbb23dde47fb4075091e5f42","key":["3566120224","2014-05-05T15:42:06Z"],"value":1},
{"id":"970c3a0fdbb23dde47fb4075091dd992","key":["3566120224","2014-05-05T15:46:26Z"],"value":1},
{"id":"970c3a0fdbb23dde47fb4075091d3853","key":["3566120224","2014-05-05T15:50:47Z"],"value":1},
{"id":"970c3a0fdbb23dde47fb4075091c9a3c","key":["3566120224","2014-05-05T15:55:07Z"],"value":1},
{"id":"970c3a0fdbb23dde47fb4075091bf465","key":["3566120224","2014-05-05T15:59:27Z"],"value":1},
{"id":"970c3a0fdbb23dde47fb4075091ba442","key":["3566120224","2014-05-05T16:03:47Z"],"value":1},
{"id":"970c3a0fdbb23dde47fb4075091ad482","key":["3566120224","2014-05-05T16:08:08Z"],"value":1},
{"id":"970c3a0fdbb23dde47fb4075091a2130","key":["3566120224","2014-05-05T16:12:28Z"],"value":1},
{"id":"970c3a0fdbb23dde47fb40750919a6ef","key":["3566120224","2014-05-05T16:16:48Z"],"value":1},
{"id":"970c3a0fdbb23dde47fb407509192479","key":["3566120224","2014-05-05T16:21:08Z"],"value":1},
{"id":"970c3a0fdbb23dde47fb40750918a977","key":["3566120224","2014-05-05T16:25:29Z"],"value":1},
{"id":"970c3a0fdbb23dde47fb40750917b468","key":["3566120224","2014-05-05T16:29:49Z"],"value":1},
{"id":"970c3a0fdbb23dde47fb407509170583","key":["3566120224","2014-05-05T16:34:09Z"],"value":1}
]}
I have two times the same data(date & dated[ms date]), 1399305161 that is = 2014-05-05T15:52:42Z
thinking that I could order the results with a data type more easy to parse for couchdb, but didn't work using the dated field
Also I don't need the id field, how can exclude it from the results?
If you look here, you can see that reverse is not a supported query option. To reverse the data, you want to do:
myview?endkey=["3566120224"]&startkey=["3566120224",{}]&descending=false
If you don't want the ID field, you can just return the reduced value at the highest grouping level:
myview?endkey=["3566120224"]&startkey=["3566120224",{}]&descending=false&group_level=2
To remove the doc.i just write:
function(doc) {
if(doc.i && doc.date){
emit([doc.date],1); // just removed doc.i
}
}
To reverse the results:
You can either change the results so that you use the descending option. I'd think that is bad practice though as it depends on the client using this feature.
Assuming it's the default use of the view, I'd opt to returning the date as integer. Date.parse(doc.date).valueof() should do the trick of returning the epoch time as integer or double. If you then return this with a '-' (minus) the view will by default be sorted in descending order. This is assuming you don't need the formatted date in the key.

sort by tags with weight in mongodb and maybe redis

I am trying to list items according to how 'important' their tags are.
Here is an example of an item:
{
name: 'item1',
tags: [1, 2, 3]
}
And here is an example of a tag
{
_id: 1,
name: red,
weight: 0.7
}
I am trying to find out the best way to sort a list of items where a lot of calculations must be made.
I imagine that sorting in real time might not be the best way and resorting to something like redis might be necessary.
By doing so I would store all the data relevant to calculate the sorting positions in redis right ?
Any input will be greatly appreciated!

couchDB sorting complex key

I have a couchDB database which has several different document "types" which all relate to a main "type".
In the common blog / post example, the main type is the blog post, and the others are comments (though there are 3 different types of comments.
All of the types have a date on them, however, I wish to sort blog posts by date, but return all of the data from the comments as well. I can write an emit which produces keys like so:
[date, postID, docTypeNumber]
where docTypeNumber is 1 for post and > 1 for the different comment document types.
e.g:
["2013-03-01", 101, 1]
[null, 101, 2]
[null, 101, 2]
[null, 101, 3]
["2013-03-02", 101, 1]
[null, 102, 2]
[null, 102, 3]
Of course, If I emit this, all the nulls get sorted together. Is there a way to ignore the nulls, and group them by the seccond item in the array, but sort them by the first if it is not null?
Or, do I have to get all the documents to record the post date in order for sort to work?
I do not want to use lists, they are way too slow and I'm dealing with a potentially large data set.
You can do this by using conditionals in your map function.
if(date != null) {
emit([date, postID, docTypeNumber]);
}
else {
emit([postID, docTypeNumber]);
}
I don't know if you want your array length to be variable or not. If not, you could add the sort variable first. The following snippet could work since date and postID presumably never have the same values.
if(date != null) {
sortValue = date;
}
else {
sortValue = postID;
}
emit(sortValue, date, postID, docTypeNumber);
Update: I thought about this a little more. In general, I make my views based on queries I want to perform. So I ask myself, what do I need to query? It seems that in your case, you might have two distinct queries here. If so, I suggest having two different views. There is a performance penalty to pay since you would run two views instead of one, but I doubt it is perceivable to the user. And it might take up more disk space. The benefit for you would be clearer and more explicit code.
It seems you want to sort all the data (both the post and the comments) with post's date. Since in your design comment document does not contain post date (just comment date) it is difficult with the view collation pattern. I suggest changing the database design to have blog post ID meaningful and contain the date, eg. concatenated date with author id. This way if you emit [doc._id, doc.type] from the post and [doc.post, doc.type] from the comment document you will have post and comments grouped and sorted by date.

Mongodb: How to order a "select in" in same order as elements of the array

I'm performing this mongo query:
db.mytable.find({id:{$in:["1","2", "3", "4" ]}});
It returns all results in a strange order, as it follows:
4,3,2,1
I need to retrieve all results in same order as it was defined in the query array.
1,2,3,4
Is it possible ?
There is indeed no guarantee about the order of results returned from your query, but you could do a sort afterwards with the result. Two examples, the first one with the order you wanted, the second one reversed.
const arr = ["1", "2", "3", "4" ];
db.collection.find({ id: { $in: arr }})
.then(result => {
let sorted = arr.map(i => result.find(j => j.id === i));
console.log(sorted) // 1, 2, 3, 4
let reversed = arr.reverse().map(i => result.find(j => j.id === i));
console.log(reversed) // 4, 3, 2, 1
});
In case you want to do real MongoDB ID lookups, use db.collection.find({ _id: { $in: arr }}) and .map(i => result.find(j => j._id == i)) (Notice the two equal signs instead of three)
A couple of things to note:
1.) MongoDB, like most databases, makes no guarantees about the order of results returned from your query unless you use a call to sort(). If you really want to guarantee that your query result is returned in a a specific order, you'll need to specify that specific sort order.
2.) In general, the most recently updated/moved document will show up at the end of your result set but there are still no guarantees. MongoDB uses "natural order" for its native ordering of objects and although this is very close to the order of insertion, it is not guaranteed to be the same.
3.) Indexed fields will behave differently. It's worth pointing out that it looks like your query is using id and not _id. The former, _id would be indexed by default and id would not be indexed unless you've explicitly added an index to that field.
You can read more about MongoDB's sorting and ordering here:
http://www.mongodb.org/display/DOCS/Sorting+and+Natural+Order
you can write a query like this :
db.mytable.find({id:{$in:["1","2", "3", "4" ]}}).sort({id:1})
To have your results ORDER BY id ASC
Source : MongoDB Advanced Queries
But if you just want to order the results based on your $in array, try to sort your $in array in the reverse order, the result regarding to the first element of your $in array is likely to appear as the last element of the results

Resources