Using mongodb, how can I remove an object from an array based on one of its properties? - node.js

I have a mongodb collection containing an array of objects, and I'd like to remove one or more of the array objects based on their properties.
Example document from my collection:
nickname: "Bob",
isLibrarian: false,
region: "South America",
favoriteBooks: [
{
title: "Treasure Island",
author: "Robert Louis Stevenson"
},
{
title: "The Great Gatsby",
author: "F. Scott Fitzgerald"
},
{
title: "Kidnapped",
author: "Robert Louis Stevenson"
}
]
In this example, how do I remove, from each of the documents in my collection, all objects within the favoriteBook array whose author matches "Robert Louis Stevenson"?
So that afterwards this user document would be
nickname: "Bob",
isLibrarian: false,
region: "South America",
favoriteBooks: [
{
title: "The Great Gatsby",
author: "F. Scott Fitzgerald"
}
]
and other documents in the collection would be equally trimmed of books by Stevenson.
Thank you in advance for any insight! I love MongoDB but I'm wondering if I've bitten off more than I can chew here...

The below line of mongodb will help you to delete the books that matches a particular author
db.collection.update(
{},
{$pull:{favoriteBooks:{author:"Robert Louis Stevenson"}}},
{multi:true}
);

Related

How to use auto increment in mongoose?

Hi I'm using mongoose for mongooDB in node.js,
lets say I have a school DB'
there is a a collection of grades and a collection of students.
each student is associated to a grade.
I want to create an auto increment filed which wiil be the student serial number.
the problem is that each grade has different counting.
for example:
Grades Collection:
{
{grade:A, teacher: "Mr. Smith" },
{grade:B, teacher: "Mrs. Jones" },
}
Students Collection:
{
{name:"Abe", grade:A, serialNumber:1 },
{name:"John", grade:A, serialNumber:2 },
{name:"Mary", grade:A, serialNumber:3 },
{name:"Patricia", grade:B, serialNumber:1 },
{name:"Robert", grade:B, serialNumber:2 },
{name:"Emily", grade:A, serialNumber:4 },
}
How should I implement such a thing?

How does MongoDB $text search works?

I have inserted following values in my events collection
db.events.insert(
[
{ _id: 1, name: "Amusement Ride", description: "Fun" },
{ _id: 2, name: "Walk in Mangroves", description: "Adventure" },
{ _id: 3, name: "Walking in Cypress", description: "Adventure" },
{ _id: 4, name: "Trek at Tikona", description: "Adventure" },
{ _id: 5, name: "Trekking at Tikona", description: "Adventure" }
]
)
I've also created a index in a following way:
db.events.createIndex( { name: "text" } )
Now when I execute the following query (Search - Walk):
db.events.find({
'$text': {
'$search': 'Walk'
},
})
I get these results:
{ _id: 2, name: "Walk in Mangroves", description: "Adventure" },
{ _id: 3, name: "Walking in Cypress", description: "Adventure" }
But when I search Trek:
db.events.find({
'$text': {
'$search': 'Trek'
},
})
I get only one result:
{ _id: 4, name: "Trek at Tikona", description: "Adventure" }
So my question is why it dint resulted:
{ _id: 4, name: "Trek at Tikona", description: "Adventure" },
{ _id: 5, name: "Trekking at Tikona", description: "Adventure" }
When I searched walk it resulted the documents containing both walk and walking. But when I searched for Trek it only resulted the document including trek where it should have resulted both trek and trekking
MongoDB text search uses the Snowball stemming library to reduce words to an expected root form (or stem) based on common language rules. Algorithmic stemming provides a quick reduction, but languages have exceptions (such as irregular or contradicting verb conjugation patterns) that can affect accuracy. The Snowball introduction includes a good overview of some of the limitations of algorithmic stemming.
Your example of walking stems to walk and matches as expected.
However, your example of trekking stems to trekk so does not match your search keyword of trek.
You can confirm this by explaining your query and reviewing the parsedTextQuery information which shows the stemmed search terms used:
db.events.find({$text: {$search: 'Trekking'} }).explain().queryPlanner.winningPlan.parsedTextQuery
{
​ "terms" : [
​ "trekk"
​ ],
​ "negatedTerms" : [ ],
​ "phrases" : [ ],
​ "negatedPhrases" : [ ]
}
You can also check expected Snowball stemming using the online Snowball Demo or by finding a Snowball library for your preferred programming language.
To work around exceptions that might commonly affect your use case, you could consider adding another field to your text index with keywords to influence the search results. For this example, you would add trek as a keyword so that the event described as trekking also matches in your search results.
There are other approaches for more accurate inflection which are generally referred to as lemmatization. Lemmatization algorithms are more complex and start heading into the domain of natural language processing. There are many open source (and commercial) toolkits that you may be able to leverage if you want to implement more advanced text search in your application, but these are outside the current scope of the MongoDB text search feature.

How to implement localisation with HapiJs and MongoDB

MongoDB return the following data:
{
name: {
"en": "any name",
"ar": "اي اسم"
}
}
What can be done, if language chosen is ar and want this output:
{
name: "اي اسم"
}
Thanks!
You can use the aggregation framework built in to MongoDB, e.g.
db.LocalNames.aggregate([
{$match: {"name.ar": {$exists: true}}},
{$project: {"name": "$name.ar"}}
])
This will match only documents with an Arabic name and then project just that value as name

Making MongoDB more 'relational'

I like using MongoDB but can't quite swallow the non-relational aspect of it. As far as I can tell from mongo users and the docs: "It's fine, just duplicate parts of your data".
As I'm worried about scaling, and basically just not remembering to update parts of the code to update the correct parts of the data, it seems like a good trade-off to just do an extra query when my API has to return the data for a user with a summary of posts included:
{
"id": 1,
"name": "Default user",
"posts_summary": [
{
"id": 1,
"name": "I am making a blog post",
"description": "I write about some stuff and there are comments after it",
"tags_count": 3
},
{
"id": 2,
"name": "This is my second post",
"description": "In this one I write some more stuff",
"tags_count": 4
}
]
}
...when the posts data looks like this below:
//db.posts
{
"id": 1,
"owner": 1,
"name": "I am making a blog post",
"description": "I write about some stuff and there are comments after it",
"tags": ["Writing", "Blogs", "Stuff"]
},
{
"id": 2,
"owner": 1,
"name": "This is my second post",
"description": "In this one I write some mores tuff",
"tags": ["Writing", "Blogs", "Stuff", "Whatever"]
}
So behind the API, when the query to get the user succeeds, I am doing an additional query to the posts collection to get the "posts_summary" data I need, and adding it in before the API sends response.
It seems like a good trade-off considering the problems it will solve later. Is this what some mongo users do to get around it not being relational, or have I made a mistake when designing my schema?
You can use schema objects as references to implement relational mapping using mongoose
http://mongoosejs.com/docs/populate.html
using mongoose ur schema would be like:
User:Schema({
_id : Number,
name : String,
owner : String,
Post : [{ type: Schema.Types.ObjectId, ref: 'Post' }]
});
Post:Schema({
_id : Number,
name : String,
owner : String,
description : String,
tags:[String]
})

Is reading whole object from DocumentDb faster and more efficient?

I'm trying to understand if it would actually be more efficient to read the entire document from Azure DocumentDb than it is to read a property that may have multiple objects in it?
Let's use this basketball team object as an example:
{
id: 123,
name: "Los Angeles Lakers",
coach: "Byron Scott",
players: [
{ id: 24, name: "Kobe Bryant" },
{ id: 3, name: "Anthony Brown" },
{ id: 4, name: "Ryan Kelly" },
]
}
If I want to get only a list of players, is it more efficient/faster for me to read the entire team document from which I can extract the players OR is it better to send SQL statement and try to read only the players from the document?
Returning only the players will be more efficient on the network, as you're returning less data. And, you should also be able to look at the Request Units burned for your query.
For example, I put your document into one of my collections and ran two queries in the portal (and if you do the same, and look at the bottom of the portal, you'll see the resulting Request Unit cost). I slightly modified your document with unique ID and quotes around everything, so I could load it via the portal:
{
"id": "basketball123",
"name": "Los Angeles Lakers",
"coach": "Byron Scott",
"players": [
{ "id": 24, "name": "Kobe Bryant" },
{ "id": 3, "name": "Anthony Brown" },
{ "id": 4, "name": "Ryan Kelly" }
]
}
I first selected just player data:
SELECT c.players FROM c where c.id="basketball123"
with an RU cost of 2.2:
I then asked for the entire document:
SELECT * FROM c where c.id="basketball123"
with an RU cost of 2.24:
Note: Your document size is very small, so there's really not much difference here. But at least you can see that returning a subset costs less than returning the entire document.

Resources