Deleting a row from an embedded document in mongo engine - python

I have a document called login_info. It has two fields:
name
password
Location
Location is an embedded document with two fields:
datetime
city
There are datas in the embedded document and i want to delete a row from it.
for eg: i have to delete all the rows with location "Canada". How can i do this in mongo engine ? any help

Try this
db.login_info.update({}, {$pull:{location:{city:"Canada"}}})
Ok try this instead
db.login_info.update( { "location.city" : { $exists : true } }, { $unset : { "location.city" : "Canada" } }, false, true);
This will remove all "rows" where city is "Canada".

Related

Export part of data filed - MongoDB

I'm using MongoDB Compass to export my data as csv file, but I have only the choice to select which field I want and not elements in a specific field.
MongoDB export data:
Actually, I'm interested to save only the "scores" for object "0,1,2".
Here a ScreenShot from MongDB Compas:
It is something that I should deal with python?
One option could be to "rewrite" "scoreTable" so that there are a maximum of 3 elements in the "scores" array and then "$out" to a new collection that can be exported in full.
db.devicescores.aggregate([
{
"$set": {
"scoreTable": {
"$map": {
"input": "$scoreTable",
"as": "player",
"in": {
"$mergeObjects": [
"$$player",
{"scores": {"$slice": ["$$player.scores", 3]}}
]
}
}
}
}
},
{"$out": "outCollection"}
])
Try it on mongoplayground.net.

How to index list of object in Elasticsearch?

A document format I ingest into ElasticSearch looks like this:
{
'id':'514d4e9f-09e7-4f13-b6c9-a0aa9b4f37a0'
'created':'2019-09-06 06:09:33.044433',
'meta':{
'userTags':[
{
'intensity':'1',
'sentiment':'0.84',
'keyword':'train'
},
{
'intensity':'1',
'sentiment':'-0.76',
'keyword':'amtrak'
}
]
}
}
...ingested with python:
r = requests.put(itemUrl, auth = authObj, json = document, headers = headers)
The idea here is that ElasticSearch will treat keyword, intensity and sentiment as fields that can be later queried. However, on ElasticSearch side I can observe that this is not happening (I use Kibana for search UI) -- instead, I see field "meta.userTags" with the value that is the whole list of objects.
How can I make ElasticSearch index elements within a list?
I used the document body you provided to create a new index 'testind' and type 'testTyp' using the Postman REST client.:
POST http://localhost:9200/testind/testTyp
{
"id":"514d4e9f-09e7-4f13-b6c9-a0aa9b4f37a0",
"created":"2019-09-06 06:09:33.044433",
"meta":{
"userTags":[
{
"intensity":"1",
"sentiment":"0.84",
"keyword":"train"
},
{
"intensity":"1",
"sentiment":"-0.76",
"keyword":"amtrak"
}
]
}
}
When I queried for the index's mapping this is what i get :
GET http://localhost:9200/testind/testTyp/_mapping
{
"testind":{
"mappings":{
"testTyp":{
"properties":{
"created":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"id":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"meta":{
"properties":{
"userTags":{
"properties":{
"intensity":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"keyword":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"sentiment":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
}
}
}
}
}
}
}
}
}
}
As you can see in the mapping the fields are part of the mapping and can be queried as per need in future, so I don't see the problem here as long as the field names are not one of these - https://www.elastic.co/guide/en/elasticsearch/reference/6.4/sql-syntax-reserved.html ( you might want to avoid the term 'keyword' as it might be confusing later when writing search queries as the fieldname and type are both same - 'keyword') . Also, note one thing, the mapping gets created via dynamic mapping (https://www.elastic.co/guide/en/elasticsearch/reference/6.3/dynamic-field-mapping.html#dynamic-field-mapping ) in Elasticsearch and so the data types are determined by elasticsearch based on the values you have provided.However, this may not be always accurate , so to prevent that you can use the PUT _mapping API to define your own mapping for the index, and then prevent new fields within a type from being added to mappings.
You don't need a special mapping to index a list - every field can contain one or more values of the same type. See array datatype.
In the case of a list of objects, they can be indexed as object or nested datatype. Per default elastic uses object datatype. In this case you can query meta.userTags.keyword or/and meta.userTags.sentiment. The result will allways contains whole documents with values matched independently, ie. searching keyword=train and sentiment=-0.76 you WILL find document with id=514d4e9f-09e7-4f13-b6c9-a0aa9b4f37a0.
If this is not what you want, you need to define nested datatype mapping for field userTags and use a nested query.

Delete a list item from an Embedded Document MongoEngine

I'm having trouble to find the way to delete a list item inside an Embedded document using mongo engine.
Document structure:
{
"_id" : "id",
"user" : ObjectId("xxxxxxx"),
"invoice" : false,
"coupon" : ObjectId("xxxxxxx"),
"date" : ISODate("2017-03-31T11:32:57.467Z"),
"orders" : [
{
"products" : [
ObjectId("xxxxxxx")
]
}
],
"shipping_address" : {
},
}
Using this structure, what I want to achieve, is to delete the id inside the products list inside the orders embedded document.
Any idea? any help would be really appreciated

Find in referenced/linked MongoDB document, using pymongo

I have 3 linked documents like:
{'_id':1, 'name':'abc', 'label':'actionA', 'prev':null}
{'_id':2, 'name':'pqr', 'label':'actionB', 'prev':ObjectId('1')}
{'_id':3, 'name':'xyz', 'label':'actionC', 'prev':ObjectId('2')}
Now I want to query a document whose 'name' is 'pqr' and also its previous/linked document should contains 'label' as 'actionA'.
All I want is it should find 'name' and check whether previous liked doc is available, if so then check its previous doc should have 'label' which I want.
It will be preferable if using some 1 line command something like:
db.collection.find({'$and'[{'name':'pqr'},{'prev': <gotoprev>({'label':'actionA'})}]})
you can achieve this using aggregation
MongoDB 3.4 Solution
take advantage of the $graphLookup operator:
db.collection.aggregate([
{
$match:{
"name":"pqr"
}
},
{
$graphLookup:{
from:"collection",
startWith:"$prev",
connectFromField:"prev",
connectToField:"_id",
as:"parent",
maxDepth:1,
restrictSearchWithMatch:{
label:"actionA"
}
}
}
])
Mongodb 3.2
filter out document where name != 'pqr' in a $match stage
link parent an child with $lookup
unwind the resulting array with $unwind
finally filter out document where parent.label != 'actionA'
here is the query:
db.collection.aggregate([
{
$match:{
"name":"pqr"
}
},
{
$lookup:{
from:"collection",
localField:"prev",
foreignField:"_id",
as:"prev"
}
},
{
$unwind:"$prev"
},
{
$match:{
"prev.label":"actionA"
}
}
])
You can denormalise and store prev_label also in the referenced document (NoSQL way).
{'_id':1, 'name':'abc', 'label':'actionA', 'prev':null}
{'_id':2, 'name':'pqr', 'label':'actionB', 'prev':ObjectId('1'),'prev_label': 'actionA'}
{'_id':3, 'name':'xyz', 'label':'actionC', 'prev':ObjectId('2'),'prev_label': 'actionB'}
Then you can use find query for the result
db.collection.find({'$and'[{'name':'pqr'},{'prev_label': 'actionA'}]})
If label in original document is changed you can keep them updated in referenced documents with an update query
db.collection.update({'prev': updatedDocumentId},{'$set': {'prev_label': newLabel}}, multi=True)

Traditional SQL vs MongoDB/CouchDB for simple python app

Say I got an traditional SQL structure like so:
create table tags (id PRIMARY KEY int, tag varchar(100));
create table files (id PRIMARY KEY int, filename varchar(500));
create table tagged_files (tag_id int, file_id int);
I add some tags:
insert into table tags (tag) values ('places');
insert into table tags (tag) values ('locations');
And some files:
insert into table files (filename) values ('/tmp/somefile');
insert into table files (filename) values ('/tmp/someotherfile');
and then tag these files:
insert into table tagged_files (tag_id, file_id) values (1,1);
insert into table tagged_files (tag_id, file_id) values (1,2);
Then I can find all the files tagged with the first tag like so:
select * from files, tagged_files where id = file_id and tag_id = 1
But how do I do the same thing using NoSQL solutions like MongoDB and CouchDB?? And what NoSQL project is best suited for something like this?
For MongoDB.
Chances are you'd simply save them with the tags as:
db.Files.save({ "fn" : "/tmp/somefile", "ts" : [ { "t" : "places" }, { "t" : "locations" }] });
db.Files.save({ "fn" : "/tmp/someotherfile", "ts" : [ { "t" : "locations" }] });
Alternative is to save tags separately (ObjectId's are 12 bytes iirc):
db.Tags.save({ "t" : "places" });
db.Tags.save({ "t" : "locations" });
db.Files.save({ "fn" : "/tmp/somefile", "t" : [ { "i" : ObjectId("IdOfPlaces") }, { "i" : ObjectId("IdOfLocations") }] });
In both cases to get a file it's
db.Files.find({ "_id" : ObjectId("4c19e79e244f000000007e0d") });
db.Files.find({ "fn" : "/tmp/somefile" });
Or a couple files based on tags:
db.Files.find({ ts : { t : "locations" } })
db.Files.find({ t : { i : ObjectId("4c19e79e244f000000007e0d") } })
Examples are from the mongo console. And if you store tags with Id's you'd obviously have to read the tags up based on the Id's once you got the file(s).

Categories

Resources