Updating a deeply nested object in mongodb - mongodb

I'm trying to update the favorite Boolean to true in the following model.
I only need a success/failure return, so I've been trying update with a projection. However, I can't seem to get any further than selecting articles, but am not able to change the favorite value given the title name.
I am using the mongoDB node.js driver
Thanks!
_id: id,
news: [
{
name: bbc,
articles: [
{
title: 'flashpoint', favorite: false
}
]
}
]

You're actually hitting one of the limitations of MongoDB, a Ticket on their Jira was opened in 2010 regarding updating items in deeply nested arrays, and has just been implemented, stated for release with Mongo 3.5.12. If you're using an older version, the simplest solution would be to go for a second collection containing your articles (with references on the first collection), so you can update them directly.

Related

What is the best way to structure the database for tag based fetching in cloud database

I am confused the way i need to structure my documents to effectively search/fetch items by tag when needed.
Meaning,structure of each document goes like:
{
name: "Delicious blackforest cake",
tags: ["blackforest","birthday","designer"]
...
}
{
name: "Red velvet cake",
tags: ["party","anniversary","designer"]
...
}
...
There's total of 32 tags , and i want to fetch the cakes based on tags.This is my present structure which i feel would be inefficient while fetching.
And I want to search based on tags and name of the cake, for example
if i search de
The search suggestions should be
designer cake /* This is based on tag */
Delicious blackForest cake /* This is based on actual name */
As per my knowledge i guess this is difficult to achieve in firebase. Should i opt for mongoDb or should i change the structure of the document.
I want suggestion to effectively search and fetch according to my above stated needs.
Firestore can be used for this use case. The array-contains operator can be used to query documents where tags array contains a specific value.
await colRef.where("tags", "array-contains", "tag")
If your use case required to find documents with multiple tags, then you might have to use a map instead of array. Checkout Firestore search array contains for multiple values.
MongoDB has a $all operator that can be used for this as shown below:
await collection.find({ tags: { $all: ["tag"] } })
For full-text search, you'll have to use a search service as also mentioned in the documentation for best results. Although MongoDB has a $search operator (uses Apache Lucene as far as I know), it can be used only when you host your database on Atlas otherwise you'll have to rely on $text operator.
Firestore Algolia Extension should do most of the work for you and let you use all full text search capabilities of Algolia.
Additionally, if you use Algolia with Firestore, you can get even better support for filtering by tags so you won't have to use a map instead of array as mentioned earlier.

Mongo roblox API wrapper issue

I'm using Roblox's Mongo API wrapper
https://devforum.roblox.com/t/rbx-to-mongo-a-mongodb-data-api-wrapper/1661288
However, I'm having some issues with it.
Here is my data source for mongo:
My Data Source
I'm trying to get a table of all "tokens" in a table
Lua code
It just returns an empty table.
Per the additional information in the comments, it doesn't look like you have a matching document in the database.
Currently your query is looking for a document that is similar to the following:
{
_id: 1,
name: "tokens"
}
But the document from the screenshot resembles the following instead:
{
_id: 6,
tokens: [ 1, 2, 4 ]
}
You can see a demonstration of that in this Mongo Playground.
The changes that you need to make depend on what you are trying to do. If you are trying to find a document that has a specific value in the tokens array, then you may be looking for a filter similar to { tokens: 4 }. If instead you just want to retrieve a document that has a tokens field, then you may be looking for a filter such as { tokens: { $exists: true } }.

custom sort for a mongodb collection in meteor

I have this collection of products and i want to display a top 10 products based on a custom sort function
[{ _id: 1, title, tags:['a'], createdAt:ISODate("2016-01-28T00:00:00Z") } ,
{ _id: 2, title, tags:['d','a','e'], createdAt:ISODate("2016-01-24T00:00:00Z") }]
What i want to do is to sort it based on a "magic score" that can be calculated. For example, based on this formula: tag_count*5 - number_of_days_since_it_was_created.
If the first one is 1 day old, this makes the score:
[{_id:1 , score: 4}, {_id:2, score: 10}]
I have a few ideas on how i can achieve this, but i'm not sure how good they are, especially since i'm new to both mongo and meteor:
start an observer (Meteor.observe) and every time a document is
modified (or a new one created), recalculate the score and update it
on the collection itself. If i do this, i could just use $orderBy
where i need it.
after some reading i discovered that mongo aggregate or map_reduce
could help me achieve the same result, but as far as i found out,
meteor doesn't support it directly
sort the collection on the client side as an array, but using this
method i'm not sure how it will behave with pagination (considering that i subscribe to a limited number of documents)
Thank you for any information you can share with me!
Literal function sorting is just being implemented in meteor, so you should be able to do something like
Products.find({}, {sort: scoreComparator});
in an upcoming release.
You can use the transform property when creating collection. In this transform, store the magic operation as a function.
score=function(){
// return some score
};
transformer=function(product){
product.score=score;
// one could also use prototypal inheritance
};
Products=new Meteor.Collection('products',{transform:transformer});
Unfortunately, you cannot yet use the sort operator on virtual fields, because minimongo does not support it.
So the ultimate fall-back as you mentioned while nor the virtual field sorting nor the literate function sorting are supported in minimongo is client side sorting :
// Later, within some template
scoreComparator=function(prd1,prd2){
return prd1.score()-prd2.score();
}
Template.myTemplate.helpers({
products:function(){
return Products.find().fetch().sort(scoreComparator);
}
});
i'm not sure how it will behave with pagination (considering that i subscribe to a limited number of documents)
EDIT : the score will be computed among the subscribed documents, indeed.

Meteor publish latest grouped by

I have a collection that with something like:
{
_id: 'abc',
_remoteId: 'xyz',
submitted_on: ISODate('2015-01-24T15:00:39.171Z"');
}
Where _remoteId is a reference to another collection. What I need is to publish the latest of documents, grouped by _remoteId. I think I need to use the $group aggregate, but the only examples (example here) seem to not return a Cursor, and thus do not seem to be reactive. Is there a way to publish a group aggregate in such a way to be reactive, either by returning a Cursor directly or by observing on the server and setting up the updates manually?
The second code snippet in the example that you reference shows how you would create a reactive cursor. He missed returning it though... at the end of the previousInviteContacts, he should have returned:
return self.ready();
Other than that, to consume it, just subscribe to the previousInviteContacts publication and query the contacts collection.

MongoDB - Query embbeded documents

I've a collection named Events. Each Eventdocument have a collection of Participants as embbeded documents.
Now is my question.. is there a way to query an Event and get all Participants thats ex. Age > 18?
When you query a collection in MongoDB, by default it returns the entire document which matches the query. You could slice it and retrieve a single subdocument if you want.
If all you want is the Participants who are older than 18, it would probably be best to do one of two things:
Store them in a subdocument inside of the event document called "Over18" or something. Insert them into that document (and possibly the other if you want) and then when you query the collection, you can instruct the database to only return the "Over18" subdocument. The downside to this is that you store your participants in two different subdocuments and you will have to figure out their age before inserting. This may or may not be feasible depending on your application. If you need to be able to check on arbitrary ages (i.e. sometimes its 18 but sometimes its 21 or 25, etc) then this will not work.
Query the collection and retreive the Participants subdocument and then filter it in your application code. Despite what some people may believe, this isnt terrible because you dont want your database to be doing too much work all the time. Offloading the computations to your application could actually benefit your database because it now can spend more time querying and less time filtering. It leads to better scalability in the long run.
Short answer: no. I tried to do the same a couple of months back, but mongoDB does not support it (at least in version <= 1.8). The same question has been asked in their Google Group for sure. You can either store the participants as a separate collection or get the whole documents and then filter them on the client. Far from ideal, I know. I'm still trying to figure out the best way around this limitation.
For future reference: This will be possible in MongoDB 2.2 using the new aggregation framework, by aggregating like this:
db.events.aggregate(
{ $unwind: '$participants' },
{ $match: {'age': {$gte: 18}}},
{ $project: {participants: 1}
)
This will return a list of n documents where n is the number of participants > 18 where each entry looks like this (note that the "participants" array field now holds a single entry instead):
{
_id: objectIdOfTheEvent,
participants: { firstName: 'only one', lastName: 'participant'}
}
It could probably even be flattened on the server to return a list of participants. See the officcial documentation for more information.