I need to get a document from MongoDB and put it into a struct with custom type.
type translate_t struct {
Sources []string `bson:"sources"`
Targets []string `bson:"targets"`
}
type practice_t struct {
Id primitive.ObjectID `bson:"_id"`
Translate translate_t `bson:"translate"`
}
The data in the database is as expected.
"practice": {
"translate": {
"sources": ["data", "more data"]
"target": ["even", "more", "data"]
}
}
What I do (very basic):
var item practice_t
err = collection.FindOne(ctx, filter).Decode(&item)
log.Printf("item:%+v", item)
The log prints this:
{Id:ObjectId("5deeblablabla"), Translate:{Sources:[] Targets:[]}} //where is my sweet data?
Now, I want to point out that all the other items (not nested with custom struct) get decoded properly. So, it seems to me that the Decode() function doesn't like custom structs...
This looks like a very common task, so am I missing anything?
I've been reading about overriding the default Decoder or something like that, but that seems way too much work for something this simple.
You are missing "practice":
type doc struct {
Practice practice_t `bson:"practice"`
}
The database document has to structurally match the document you're unmarshaling. You showed the database document is an object with a practice field. Then you must have a struct with a field tagged with practice.
Related
I am trying to fetch a random record from my Swift Realm database.
I have previously used the sample function in mongoDB, so I thought there must be an equivalent in Realm (it's based on mongoDB, right?)
I can't find any documentation on such a function, and I've only found search results which suggest to fetch the entire collection then choose a random record [1, 2]. Obviously, this is inefficient.
Am I missing something obvious, is there a better way to do it?
See below for an example mongoDB query:
db.Words.aggregate([
{ $match: { gender: gender } },
{ $sample: { size: 1 } }
])
For clarity the code in the question is not part of the Realm Swift SDK for local or sync but it is a query directly to Atlas using app services, so it would be valid for non-sync'ing or non-local applications. (Use the Swift SDK if possible!)
If we're doing this using the SDK, you can actually leverage high-level Swift functions to return a result using .randomElement()
So given a PersonClass that has a name property
class PersonClass: Object {
#Persisted var name = ""
}
we can this use this code to return a random person from Realm and output their name to console
if let randomPerson = realm.objects(PersonClass.self).randomElement() {
print(randomPerson.name)
} else {
print("no data was returned)")
}
I have two collections in a mongo DB.
Here is how a document looks in the first collection (MainCollection):
_id
:"mzWqPEDYRU"
TITLE
:"ZAZ: I want."
ownerID
:"lGutCBY52g"
accessKey
:"0kAd4TOmoK0"
_created_at
:2020-03-13T11:42:11.169+00:00
_updated_at
:2020-03-13T17:08:15.090+00:00
downloadCount
:2
And here is how it looks in the second collection (SecondCollection):
_id
:"07BOGA8bHG"
_p_unit
:"MainCollection$mzWqPEDYRU"
SENTENCE
:"I love nature peace and freedom."
Order
:5
ownerID
:"lGutCBY52g"
AUDIO
:"07067b5589d1edd1d907e96c1daf6da1_VOICE.bin"
_created_at
:2020-03-13T11:42:17.483+00:00
_updated_at
:2020-03-13T11:42:19.336+00:00
There is a parent children relationship between the first and the second collection. In the last document we can see the _p_unit field where the "mzWqPEDYRU" part points to the id of the parent in the first collection.
I have one problem from start with the following code:
func theFunction() {
do {MainCollection.query().find() {
result in
switch result {
case .success(let items):
print("items.count = \(items.count)")
for item in items {
/// ....
}
case .failure(let error):
print("Error in \(#function): \(error)")
}
}
}
}
The way this above code is written works fine and I get the number of elements in MainCollection as one would expect. But then comes a less expected behaviour, in this same code if I replace MainCollection by SecondCollection, instead of getting the number of elements in SecondCollection as I would think. I get an error like:
ParseError(code: ParseSwift.ParseError.Code.unknownError,
message: "Error decoding parse-server response:
Optional(<NSHTTPURLResponse: 0x2837211a0> { URL:}
{ Status Code: 200, Headers {} }) with error:
The data couldn’t be read because it isn’t in the correct format.
Format: Optional(\"{\\\"results\\\": .......
Can anybody point out what is causing this?
It is something like:
var SecondCollection.query(unit == documentOne).find()
The .query() method works in a key/value scheme so it should pass the key as a string and the value as the referenced type, so passing "unit" between double quotes is correct:
do {SecondCollection.query("unit" == cell).find() {
The error you're getting is because cell is a Parse.Object and it is expecting a value in that place (a property in this case).
Please try the following and see if it works for you:
do {SecondCollection.query("unit" == cell.id).find() {
I have the following model in an Angular 6 cli/TS/AngularFire thing I'm trying to build. I'm new to all of those things.
export class Book {
constructor(
public id: string,
public title: string,
public genres: any[]
) {}
}
And I want to be able to find all books that matcha genre stored in Firebase's Cloud Firestore using AngularFire2.
A standard query looks like this (documentation):
afs.collection('books', ref => ref.where('size', '==', 'large'))
Ideally, I want to make a call to Firebase that doesn't get all documents in the collection so it's more efficient (tell me if that's wrong thinking). For example, something like this.
afs.collection('books', ref => ref.where(book.genres.containsAny(array of user defined genres)));
I have a limited understanding of NoSQL data modeling, but would happily change the model if there's something more effective that will stay fast with 1000 or 30,000 or even 100,000 documents.
Right now I am doing this.
filterArray = ["Genetic Engineering", "Science Fiction"];
filteredBooks: Book[] = [];
ngOnInit() {
this.db.collection<Book>('books')
.valueChanges().subscribe(books => {
for (var i=0; i < books.length; i++) {
if (books[i].genres.some(v => this.filterArray.includes(v))) {
this.filteredBooks.push(books[i]);
}
}
});
}
This works to filter the documents, but is there a more efficient way both in terms of speed and scalability (get only the matching documents instead of all)?
You're right to limit the documents first. You don't want to pull 30K documents, THEN filter them. And you are on the right path, but your formatting wasn't quite right. You want to do something like this:
afs.collection<book>('books', ref => ref.where('genres', 'array-contains', genre)
I believe that as of right now, you cannot pass in an array like:
afs.collection<book>('books', ref => ref.where('genres', 'array-contains', genres) // note that genres is plural implying a list of genres
However, it still may be better to do a for-loop through the genres and pull the books list, once for each genre, and concatenate the lists afterward.
Now, you mentioned that you would also like a suggestion to store the data differently. I would recommend that you do NOT use an array for genres. Instead make it a map (basically, an object), like this:
author: string;
title: string;
...
genres: map
Then you can do this:
author: 'Herman Melville'
title: 'Moby Dick'
...
genres: {
'classics': true
'nautical': true
}
And then you can filter the collection like this:
afs.collection<book>('books', ref => ref.where('genres.classics', '==', true).where('genres.nautical', '==' true)
I hope this helps
I'm currently using mongoose v. 5.25, against mongoDB v.3.6.
My application is supposed to query data from many different views, for instance, a view I currently have at my DB: db.joboffers_view.find()
will return many records that have been aggregated from different collections.
For a normal collection model, I query it like so:
const model = db.model(attribute);
/*where attribute, can be any registered schema */
model.find().
then((result) => {
resolve(result);
}).
catch((err) => {
reject(err);
});
Then way I register my models is something like this (simplified code):
//...
//abstracting boring connection methods
const db = mongoose.connection
//...
//simple model schema
const users_schema = {
_id: ObjectId,
another_field: String
};
//here I'm registering a schema for a VIEW, instead of normal collection
const view_schema = {
_id: ObjectId,
another_field: String
};
//...
//then
db.model('users', users_schema);
db.model('view', view_schema);
When I run a query from any of my registered models, I get the results just fine. However, when I run it against a model that represents a view on my mongo database, it returns an empty array.
No errors, no nothing, just an empty array.
I have looked through mongoose documentation, and I didn't find any specific method or pattern for querying a view, instead of a collection data.
It seems to be the same way I would do for any other collection I have in my system.
Am I missing something?
I also faced the same issue and figured out the problem is that mongoose, by default, reads collection names by pluralizing the model/view name.
So when you create any view and want to use it in mongoose, either make sure your view name is plural (add s to end of view name) or pass a collection name when initializing a schema.
Example
const users_schema = {
_id: ObjectId,
another_field: String
};
mongoose.model('vw_user_info', users_schema, 'vw_user_info');
I have same problem, but i solved it, please check the name of the view in mongodb, it must be same with db.model('view_name', view_schema);
You can open Mongoose debug by config like this mongoose.set('debug', true);
Add 3rd argument
db.model('view', view_schema, 'view_name_in_db')
I want to load and cast a structure from a mongoDB with a few different document types that can nest them-selfes. Let's say we have three different struct types, with one parent and two children
type Parent struct {
ID bson.ObjectId `bson:"_id,omitempty`
Title string
Description string
NestedObjects []*Parent
}
type ChildA struct {
Parent
DateFrom time.Time
DateTo time.Time
}
type ChildB struct {
Parent
Options []string
}
The idea is to have a root-document holding other ChildA or ChildB documents. So an example document could look like this:
{
"Title": "test event",
"Description": "description goes here",
"NestedObjects": [
{
"Title": "test event",
"Description": "description goes here",
"NestedObjects": [],
"Options": ["foo", "bar"]
}
],
DateFrom: ISODate(...),
DateTo: ISODate(...)
}
How can I now cast them dynamically into a struct (of the correct type)? The root-document is of the Type ChildA and the first nested document of the type ChildB. And the result I want is some kind of static type []Parent which can be dynamically be casted to the sub types, somehow like this (pseudo-code)
for _ ele := range results {
if ele typeof ChildA {
...
}
if ele typeof ChildB {
...
}
}
(Just for some explaination: I want to build events like ToDo Lists, Polls, and some others which can contain each other. So like a event "Netflix&chill" can have a Poll & ToDos, example: ToDos: "Buy popcorn", "Decide which movie to watch -> [Poll: "Jurassic Park", "Inception", ...]".)
First of all your NestedObjects []*Parent is a slice of Parents, not children.
Secondly, it is not clear how you are going to discriminate your children and what you would expect in the result of, for example, Collection.Find().One(?)
It may worth to read Unstructured MongoDB collections with mgo for good examples of how to use bson.* types.