Implementing Mongo Atlas Search on a Document that has dynamic properties - mongodb

I am having trouble implementing an Atlas Search on a document collection where the documents have no fixed field names. All the field names are highly dynamic.
For Example, A user may create a document with the following fields
{
name: string,
description: string
}
Another user may create a document with the following fields
{
company: string,
username: string
}
This is happening because we provide a feature to users where they can create their own records. So the fields are also dynamic depending on their needs. No, we need to provide Full-Text Search Support on these documents but we are struggling to create a Search Index because the path is dynamic.
Is there any way in Mongo Atlas Search to accomplish this?

Yes, when you define the collections [field mapping] you want to define it as dynamic:
You can configure Atlas Search to automatically index all the supported field types in the collection using dynamic mappings.
There are some limitations by doing this but it does not sounds like it will affect you.
You then can execute a wildcard field search

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.

MongoDB. Searching substring in string field

Currently, I have a MongoDB instance, which contains a collection with a lot of entities. Each entity contains a string attribute, which represents some text. My goal is to provide a strict text search in the collection. It should work as a MySQL query:
SELECT *
FROM texts
WHERE text LIKE '%test%';
MongoDB text index would be great, but it doesn't provide a strict search. How I could organize a strict search for such data? Could I do some optimization?
I already checked other software (such as ElasticSearch, Lucene, MongoDB, ClickHouse), but I haven't found options to do it. Searching as now took too much time.
In mongoDB you can do it as follow:
db.texts.find({ text:/test/ })

Put a prefix for ObjectID for MongoDB _id field

I'm trying to put a prefix before the auto generated _id, to identify from which collection came an id, but I still want to use the mongo unique id generator.
So I can know that this id model_5e1a51821c9d44000089e3e0 came from the Model collection.
Is there a solution for that without messing with random string ?
Edit
The _id need to be string castable, since I use it as id in a graphQL object. I need to differentiate ids because I use an union in my schema and resolver need to know in which table to find the data.
The _id can be generated within an application with the constructor ObjectId(). If you want to add a prefix for the generated field, you can use an embedded document as a field for the _id, like this:
_id: {
idPrefix: "Model",
_id: ObjectId("5e1bd112b7f18a490a4bafb5")
}
Other way of identifying if a document is from another collection is use a separate boolean field:
{
_id: ObjectId("5e1bd112b7f18a490a4bafb5"),
isFromModel: <boolean true or false>,
...
}
There are some options available to do this, I'm just trying to tell you the way how would I do if I need this.
Step 1: You can generate the document and it will return you ObjectId (_id) .
Step 2: Take that value and prefix it with model like this.
let _id=5e1a51821c9d44000089e3e0;let new_idValue="model_"+_id;
Step3: Now update your document by _id and push new value in place of if as
this.db.document.findByIdAndUpdate(_id,{$set:{{_id:new_idValue}})
This is what you can do. If you find some best solution than mine, let me know as well. I will highly appreciate.

ElasticSearch indexing and references to other documents

I have an ElasticSearch instance indexing a MongoDB database using the river by richardwilly98
There are two types of documents that are indexed:
documents referencing users
documents representing users
When these objects are added to mongodb richardwilly98's river generates something like the following:
document = {'user': {"$id" :
"5159a004c87126641f4f9530" } }
user_document = {'_id':"5159a004c87126641f4f9530",'username':'bob'}
If I perform a search for 'bob' i'd like any documents that reference the bob document to be returned. At the moment this doesn't happen because the username field is not related to the referencing documents in anyway.
Is it possible to do this? Does ElasticSearch have object references?
Thanks - let me know if I haven't been clear.
If each document belong to no more than one user, you can index documents as children of users. Then you can use has_parent filter to perform the search. However, if a single document can belong to more than one user, you will have to perform search in two steps. First you would have to find the user and then issue another search to find documents.
Elasticsearch supports parent field [1]. MongoDB river supports custom mapping [2] so _parent can now be used.
http://www.elasticsearch.org/guide/reference/mapping/parent-field/
https://github.com/richardwilly98/elasticsearch-river-mongodb/issues/64

Confusion regarding Mongo db Schema. How to make it better?

I am using mongoose with node.js for this.
My current Schema is this:
var linkSchema = new Schema({
text: String,
tags: array,
body: String,
user: String
})
My use-case is this: There are a list of users and each user has a list of links associated with it. Users and links are different Schemas of course. Thus, how does one get that sort of one to one relationship done using mongo-db.
Should I make a User Schema and embed linkSchema in it? Or the other way around?
Another doubt regarding that. Tags would always be an array of strings which I can use to browse through links later. Should it be an array data type or is there a better way to represent it?
If it's 1:1 then nest one document inside the other. Which way around depends on the queries, but you could easily do both if you need to.
For tags, you can index an array field and use that for searching/filtering documents and from the information you've given that sounds reasonable IMHO.
If you had a fixed set of tags it would make sense to represent those as a nested object with named fields perhaps, depending on queries. Don't forget you not only can create nested documents in Mongo but you can also search on sub-fields and even use entire nested documents as searchable/indexable fields. For instance, you could have a username like this;
email: "joe#somewhere.com"
as a string, and you could also do;
email: {
user: "joe",
domain: "somewhere.com"
}
you could index email in both cases and use either for matching. In the latter case though you could also search on domain or user only without resorting to RegEx style queries. You could also store both variants, so there's lots of flexibile options in Mongo.
Going back to tags, I think your array of strings is a fine model given what you've described, but if you were doing more complex bulk aggregation, it wouldn't be crazy to store a document for every tag with the same document contents, since that's essentially what you'd have to do for every query during aggregation.