Find query result to List - mongodb

I have got a database filled with documents like the following :
{
"_id" : ObjectId("56zeffb2abcf7ff24b46"),
"id_thing" : -1,
"data" : {
"info1" : 36.0709427,
"date" : ISODate('2005-11-01T00:33:21.987+07:00'),
"info2" : 24563.87148077
}
}
My find method returns a List which I operate some operations over:
for (d <- result_of_find_method_here)
{
val l_d = d("data")
}
But I would like to l_d a List which is currently not, and the toList method does not work.
How do I retrieve all the fields and their value of the data container as a list?
EDIT:
I have tried multiple methods, and none work because neither applies to AnyRef which is what I get when I iterate through the l_d with a foreach loop.

Find method returns a list because there are more objects returned.
l_d is not a list, because d['data'] is not a list is a key value store: a dictionary, json or map in Scala. The question is how do you want to represent this data?
Maybe you want to take out the values from the map as a list.
You can convert map to list using: l_d.toList or map values to list: l_d.values.toList

Related

Getting distinct values from object array MongoDB

{
"_id" : NUUID("f5050a5d-b3be-4de6-a135-a119436fb511"),
"CoursesData" : [
{
"Name" : "Naturgræs",
"Value" : 1
}
],
"FacilityType" : {
"_id" : NUUID("a1b4844b-518b-40e2-8aa5-8ee399ac2d4e")
}
}
I want to retrieve a list with the distinct values from the field Name inside my object array of CourseData. Filtered by FacilityType._id. I tried using both $facet and the distinct operator, but it doesn't seems to like object arrays.
My result should look like this (or similar):
FacilityType (a1b4844b-518b-40e2-8aa5-8ee399ac2d4e),
CourseData: [Name1, Name2, Name3]
Update
From the answer given below, this is how you do it with the C# driver, if anyone needs to do the same.
FieldDefinition<FacilityDocument, string> field = "CoursesData.Name";
var result = FacilityCollection.Distinct(field, Builders<FacilityDocument>.Filter.Eq(x => x.FacilityType.ID, new Guid("a1b4844b-518b-40e2-8aa5-8ee399ac2d4e"))).ToList();
You can use distinct(). It will return distinct element for a specific field from document which match a query
For example if you want distinct value of Name field for facility "a1b4844b-518b-40e2-8aa5-8ee399ac2d4e", run this query:
db.collection.distinct("CoursesData.Name", {"FacilityType._id": "a1b4844b-518b-40e2-8aa5-8ee39ac2d4e"})
it will return :
[ "Naturgræs", ... ]

MongoDb script : Cannot compare two types correctly [duplicate]

I have a straightforward tool for building collections of documents and then automatically formatting them for EPUB or LaTeX rendering, written on top of ExpressJS. I'm using Coffeescript, if that matters (I doubt it).
Using Mongoose, I have the following:
DocumentSchema = new Schema
title: String
Offrefs = new Schema
ref: { type: ObjectId }
isa: String
BinderSchema = new Schema
title: String
contains: [Offrefs]
Offrefs doesn't specify what it refers to because because I want to be able to contain some binders in other binders, to create logical collections: "These are for the printer," "These are for epub," "These are web only," etc. (I've stripped out all the miscellaneous stuff out.)
Unfortunately, I have run into queries where, for retrieved objects
(story._id == offref.ref) -> True
And the two do indeed look the same. But:
(binder._id == offref.ref) -> False
(String(binder._id) == String(offref.ref)) -> True
And a visual comparison of the two references in the last two, they are the same ID number, but the ObjectId objects don't compare correctly.
I don't want to have to do string conversions constantly, which is a strong possiblity when I'm converting these complex objects into trees of data. Tree relationships are a bear in any DB; they shouldn't be difficult in MongoDB.
How do you do ObjectId comparisons in MongoDB?
A straight == (or ===) comparison will compare the two objects by reference, not value. So that will only evaluate to true if they both reference the very same instance.
Instead, you should be using the equals method of ObjectID to compare their values:
story._id.equals(offref.ref)
As #bendytree notes in the comments, if either value could be null (and you want nulls to compare as equal), then you can use the following instead:
String(story._id) === String(offref.ref)
This goes somewhat beyond the original asked question, but I have found that the .equals method of ObjectID's will return false in some cases where a string comparison will return true even when the values are not null. Example:
var compare1 = invitationOwningUser.toString() === linkedOwningUser.toString();
var compare2 = invitationOwningUser.equals(linkedOwningUser);
var compare3 = String(invitationOwningUser) === String(linkedOwningUser);
logger.debug("compare1: " + compare1 + "; " + "compare2: " + compare2 + "; " + "compare3: " + compare3);
Output:
compare1: true; compare2: false; compare3: true
This occurred when invitationOwningUser (an ObjectID) came from a Collection created using a Mongoose schema, and linkedOwningUser (also an ObjectID) came from a Collection not created using Mongoose (just regular MongoDB methods).
Here is the document containing invitationOwningUser (the owningUser field):
{
"_id" : ObjectId("5782faec1f3b568d58d09518"),
"owningUser" : ObjectId("5781a5685a06e69b158763ea"),
"capabilities" : [
"Read",
"Update"
],
"redeemed" : true,
"expiry" : ISODate("2016-07-12T01:45:18.017Z"),
"__v" : 0
}
Here is the document containing linkedOwningUser (the owningUser field):
{
"_id" : ObjectId("05fb8257c95d538d58be7a89"),
"linked" : [
{
"owningUser" : ObjectId("5781a5685a06e69b158763ea"),
"capabilities" : [
"Read",
"Update"
]
}
]
}
So, as a bottom line for me, I'll be using the string comparison technique to compare ObjectID's, not the .equals method.

Dynamic mongo projection - a projection that uses a field in the document to determine the projection

Say I have an object like this:
{default: 'x',
types: {
x:1,
y:2,
z:3
}
}
Is it possible to select just types.x (ie a projection of {"types.x":1}) without knowing that x is the default beforehand? Making two queries is clearly possible and not what I'm looking for.
Unfortunately this is not available yet as part of the aggregation framework. However, according to this JIRA ticket, it is currently "planned by not scheduled". The only way of doing this currently is by using the map/reduce functionality. If you want to go ahead and use that, it would mean doing something as follows:
Map each document by _id and emit the appropriate key.
Since there will be only one value per key, the reduce function will not get called, but you still need to initialise the variable you use for the reduce function. You can use an empty function or an empty string.
Run map/reduce, saving the results in a collection of your choice.
In the mongo shell, it looks something as follows:
var mapper = function() {
var typeValue = this.types[this.default];
emit(this._id, typeValue);
};
var reducer = "";
db.types.mapReduce(mapper, reducer, { out : "results" } );
If you then query the results collection, you will get something as follows:
> db.results.find();
{ "_id" : ObjectId("53d21a270dcfb83c7dba8da9"), "value" : 1 }
If you want to know what the default value was, you can modify the mapper function in order to return the key as a value as well. It would look something like this:
var mapper = function() {
var typeValue = this.types[this.default],
typeKey = "types." + this.default;
emit(this._id, { key : typeKey, val : typeValue } );
};
When run, it would produce results that look as follows:
> db.results.find().pretty();
{
"_id" : ObjectId("53d21a270dcfb83c7dba8da9"),
"value" : {
"key" : "types.x",
"val" : 1
}
}
Note that this is probably a much more convoluted solution than you might want, but it's the only way to do this using MongoDB without adding more logic to your application.

Updating multiple MongoDB records in Sails.js

I need to update multiple records in mongodb.
From frontend logic , i got the array of id's as below.
ids: [ [ '530ac94c9ff87b5215a0d6e6', '530ac89a7345edc214618b25' ] ]
I have an array of ids as above , i need to update the folder field for all the records in that array.
I tried passing the id's to mongodb query as below , but still that doesn't work.
Post.native(function(err, collection) {
collection.update({
_id : {
"$in" : ids
}
}, { folder : 'X'}, {
multi : true
}, function(err, result) {
console.log(result);
});
});
Please help.
There seem to be two possible problems.
1) your ids array is not an array of ids, it's an array which has a single element which is itself an array, which has two elements. An array of ids would be `[ 'idvalue1', 'idvalue2']
2) your id values inside of arrays are strings - is that how you are storing your "_id" values? If they are ObjectId() type then they are not a string but a type ObjectId("stringhere") which is not the same type and won't be equal to "stringhere".
There is no reason to use the native method in this case. Just do:
Post.update({id : ids}, {folder : 'X'}).exec(console.log);
Waterline automatically does an "in" query when you set a criteria property to an array, and Sails-Mongo automatically translates "id" to "_id" and handles ObjectId translation for you.
Those strings look like the string representation of mongod ObjectIds, so probably what you want to do is turn them into ObjectIds before querying. Assuming you've corrected your problem with the extra level of nesting in the array, that is:
ids = ['530ac94c9ff87b5215a0d6e6', '530ac89a7345edc214618b25']
Then you want to do something like this:
oids = []
for (var i in ids)
oids.push(ObjectId(ids[i]))
db.c.find({_id: {$in: oids}})
Does that fix your problem?

RMongo dbGetQueryForKeys(), what is the structure of "keys," and how do I sub-key them?

I am trying to query a mongo database from R using RMongo and return the values of a couple nested documents.
Looking through the documentation for RMongo, I understand the following query:
output <- dbGetQueryForKeys(mongo, 'test_data', '{"foo": "bar"}', '{"foo":1}')
Where the arguments are...
db = mongo
collection = 'test_data'
query = '{"foo": "bar"}'
keys = 'Specify a set of keys to return.'
What is the 1 in '{"foo":1}'? What is the structure of this key set? Checking against this blog post, I found a format like:
result < - dbGetQueryForKeys(mongo, "items", "{'publish_date' : { '$gte' : '2011-04-01', '$lt' : '2011-05-01'}}", "{'publish_date' : 1, 'rank' : 1}")
So, apparently, the keys need the value 1?
How would I get keys for nested documents? If I wanted something like...
output <- dbGetQueryForKeys(mongo, 'test_data', '{"foo": "bar"}', '{"foo1.foo2.foo3.foo4":1,"foo1.foo2.foo3.bar4":1}')
For nested keys, I'm currently returning something more like...
X_id
1 50fabd42a29d6013864fb9d7
foo1
1 { "foo2" : { "foo3" : { "foo4" : "090909" , "bar4" : "1"}}}
...where output[,2] is a looooong string, rather than as two separate variables for the values associated with the keys foo4 and bar4, ("090909", "1") as I would have expected.
What is the 1 in '{"foo":1}'? What is the structure of this key set?
These keys are the query projections to return for read operations in MongoDB. A value of "1" means to include a specific field and "0" excludes. The default behaviour is to include all fields in the projection.
How would I get keys for nested documents?
For nested keys, I'm currently returning something more like...
1 { "foo2" : { "foo3" : { "foo4" : "090909" , "bar4" : "1"}}}
...where output[,2] is a looooong string, rather than as two
separate variables for the values associated with the keys foo4
and bar4, ("090909", "1") as I would have expected.
The RMongo driver is returning data including the embedding hiearchy.
You can reshape & flatten the result output using the RMongo dbAggregate() command and the $project operator which is part of the Aggregation Framework in MongoDB 2.2+.
If your end goal is to extract the values from the nested object for some type of downstream processing in R this will get you there. It avoids having to build an aggregation pipeline and is a simple solution to your problem. Instead of trying to get deep into the nested structure and access bar4 directly, extract the top level of the object which will provide the long string that you've referenced.
output <- dbGetQueryForKeys(mongo, 'test_data', '{"foo": "bar"}', '{"foo1.foo2.foo3.foo4":1,"foo1":1}')
Since the output is a data.frame, you can use the 'jsonlite' library to get to your data:
library(jsonlite)
foo1 <- fromJSON(output$foo1)
bar4 <- foo1$foo2$foo3$bar4