Firestore many to many relationships - How to update data? - database

Like a note app, you can set tags to a note. Also, you can search notes with tag.
Here is the firestore structure:
notes(collection)
note_1(doc)
content: 'some words...'
tags: ['apple', 'banana']
tags(collection)
tag_1(doc)
name: 'apple'
tag_2(doc)
name: 'banana'
If I change tag_1.name to 'new_apple', how shold I update note_1.tags?

You're going to have to:
Query for all notes documents where the tags array contains "apple"
Iterate the documents in the result set. For each document:
Update update the tags array in memory to remove "apple" and add "new_apple"
Write the new tags array back to the document

Related

MongoDB, invoke update in MongoDB from toplevel updateMany

I want to update a read optimized MongoDB, meaning I don't have references, only copies of itself.
relevant types:
item: {
slug: string
tag: Tag[]
}
tag: {
slug: string
count: number
}
itemsByTag: {
tagName: string
item: Item[]
}
Szenario:
Add item (db.save)
Update tags count (for ... db.findOneAndUpdate({upsert: true}))
Update tagcount in all items that have the tag ( for tag ... db.updateMany())
NOW COMES THE WEIRD PART
Get all items that have been updated (db.find())
Update items in itemsByTags (for tag for item ... db.findOneAndUpdate())
Since I have to know which items to update and update them accordingly in itemsByTags (but without some fields like _id,__v and createdAt etc.). Worst case szenario, I have all the items in the database in my software and that could be huge.
An Idea was to only insert the new item that was created, and the rest, increase the counts, but I still would get all slugs(used as Id) and counts for the tags and update only partially, but still ALL items.
I was wondering if there is a way to chain the requests in MongoDB, for example whenever the updateMany finds a matching tag and updates it, it also goes to the itemsByTag for that tag and updates the count in all those items there without sending something back to the software.

MongoDB: deleting an array value in multiple documents in one collection using pymongo

Afternoon all. I hope you can help with a problem. I am using creating a Flask app and using pymongo and I need to delete a singular array value from multiple arrays across many documents within one collection. I have recipe documents within a 'recipes' collection, and within each of them is an array ('category') that can be between 1 and 3 values in length. I have a feature available within the admin section of my site that allows for the deletion of a category from the 'categories' collection and so, to go with that, I want to delete any instances of that category value within the 'category' array on any recipe document within the recipes 'collection'.
I have managed to do this on a single document:
mongo.db.recipes.update(
{"_id": ObjectId("60df2eec9df14e58d0c698c8")},
{"$pull": {"category": category_id}}
)
but have not managed this on the collection as a whole I have determined I need to use the $all with the $pull operator on the collection using the 'update_many' query and have so far tried:
mongo.db.recipes.update_many({"category": {"$all": {"$pull": {"category": category_id}}}})
mongo.db.recipes.update_many({"$all": {"$pull": {"category": category_id}}})
mongo.db.recipes.update_many({"category": {"$pullAll": {"category": category_id}}})
None of them work. I keep getting a the error:
TypeError: update_many() missing 1 required positional argument: 'update'
Any help would be appreciated.
Read - https://pymongo.readthedocs.io/en/stable/api/pymongo/collection.html?highlight=update_many#pymongo.collection.Collection.update_many
1st parameter is filter which will be {} if you want to update all document
mongo.db.recipes.update_many(
{} // filter filter,
{} // update
)
mongo.db.recipes.update_many({ }, {"$pull": {"category": category_id}})

How to publish a mongodb array length as an additional collection field?

I have a mongodb collection with the following fields:
_id
name (string)
[items] (array of string)
secret (boolean)
I want to publish the all the _id, name fields and the item array length only (excluding the secret field) where the secret field is true.
I have read somewhere that I can add additional document properties in my find query, but my google foo does not work.
Here is what my publish method looks like without the additional items_count property:
Meteor.publish("all_items", function() {
return myItems.find(
{secret: true},
{fields:
{_id:1,name:1}
});
});
How can I create an additional field from the [item] length in my publication?
EDIT: it seems that I need to use an aggregate function and the $projectoperator. And it is not supported by meteor.
Can anyone confirm this to me (i.e. it is the only option and it is not supported)?
You can add aggregation framework support to Meteor, and then use a simple aggregation pipeline with $project stage as you mentioned, like to following:
myItems.aggregate(
[
{$match: {secret: true}},
{$project: {_id: 1, name: 1, items_count: {$size: '$items'}}}
]
)

In RethinkDB using multi indexes for tags, how to get items that match more than one tag?

Suppose I have a story table (with example data):
story
{id: 1, name: 'First Story', tags: ['plants', 'flowers', 'dog']}
{id: 2, name: 'Second Story', tags: ['flowers', 'wedding']}
{id: 3, name: 'Third Story', tags: ['plants', 'wedding']}
The story table has a multi index on the tags field.
I can get all stories that have the plants tag with:
r.table('story').getAll('plants', {index: tags})
Now how would I get all stories that have both the plants and wedding tags in an effecient manner (hopefully utilizing the tags multi index)?
The use case requires user selectable filtering on an arbitrary number of arbitrary tags.
Passing multiple arguments to getAll finds the documents that match either tag:
r.table('story').getAll('plants', 'wedding', {index: 'tags'})
A simple multi-index on tags cannot be used to match all tags. A query that doesn't use an index would look like:
r.table('story').filter(r.row('tags').contains('plants','wedding'))
It might be possible to create and use a multi-index on the powerset of tags:
r.table('story').indexCreate('tags-powerset', r.row('tags').do(powerset), {multi:true})
r.table('story').getAll(['plants', 'wedding'], {index: 'tags'})
Because of restrictions of ReQL and in the interest of efficiency, the powerset function may need to be approximated, for example as:
function(tags) {
return tags.concatMap(function(a){
tags.map(function(b){
return [a,b] })})}

MongoDB: Query and retrieve objects inside embedded array?

Let's say I have the following document schema in a collection called 'users':
{
name: 'John',
items: [ {}, {}, {}, ... ]
}
The 'items' array contains objects in the following format:
{
item_id: "1234",
name: "some item"
}
Each user can have multiple items embedded in the 'items' array.
Now, I want to be able to fetch an item by an item_id for a given user.
For example, I want to get the item with id "1234" that belong to the user with name "John".
Can I do this with mongoDB? I'd like to utilize its powerful array indexing, but I'm not sure if you can run queries on embedded arrays and return objects from the array instead of the document that contains it.
I know I can fetch users that have a certain item using {users.items.item_id: "1234"}. But I want to fetch the actual item from the array, not the user.
Alternatively, is there maybe a better way to organize this data so that I can easily get what I want? I'm still fairly new to mongodb.
Thanks for any help or advice you can provide.
The question is old, but the response has changed since the time. With MongoDB >= 2.2, you can do :
db.users.find( { name: "John"}, { items: { $elemMatch: { item_id: "1234" } } })
You will have :
{
name: "John",
items:
[
{
item_id: "1234",
name: "some item"
}
]
}
See Documentation of $elemMatch
There are a couple of things to note about this:
1) I find that the hardest thing for folks learning MongoDB is UN-learning the relational thinking that they're used to. Your data model looks to be the right one.
2) Normally, what you do with MongoDB is return the entire document into the client program, and then search for the portion of the document that you want on the client side using your client programming language.
In your example, you'd fetch the entire 'user' document and then iterate through the 'items[]' array on the client side.
3) If you want to return just the 'items[]' array, you can do so by using the 'Field Selection' syntax. See http://www.mongodb.org/display/DOCS/Querying#Querying-FieldSelection for details. Unfortunately, it will return the entire 'items[]' array, and not just one element of the array.
4) There is an existing Jira ticket to add this functionality: it is https://jira.mongodb.org/browse/SERVER-828 SERVER-828. It looks like it's been added to the latest 2.1 (development) branch: that means it will be available for production use when release 2.2 ships.
If this is an embedded array, then you can't retrieve its elements directly. The retrieved document will have form of a user (root document), although not all fields may be filled (depending on your query).
If you want to retrieve just that element, then you have to store it as a separate document in a separate collection. It will have one additional field, user_id (can be part of _id). Then it's trivial to do what you want.
A sample document might look like this:
{
_id: {user_id: ObjectId, item_id: "1234"},
name: "some item"
}
Note that this structure ensures uniqueness of item_id per user (I'm not sure you want this or not).

Resources