Hi I'm beginner in mongodb, my document looks like this :
{
'_id': ObjectId("599d142a02ae238"),
'name': 'Product One',
'status': 'in stock',
'prices': [ {
'currency': 'USD',
'amount': 1000
}, {
'currency': 'THB',
'amount': 3000
} ]
}
I would like to do a query to search for product in specific price range and specific currency. My query is looks like this:
[
'prices.amount' => ['$gte' => 2000, '$lte' => 5000],
'prices.currency' => 'USD',
]
if I run this query it should not return any value, as the product price in that range is not in USD. But it did return the data. How is the correct query? Any advice pls? Thanks
{"prices":{"$elemMatch":{"amount": {"$gte":2000, "$lte":5000}, "currency":"USD"}}}
Related
I have a List<Map<String, String>> like below
[
{ 'name': 'John', 'id': 'aa' },
{ 'name': 'Jane', 'id': 'bb' },
{ 'name': 'Lisa', 'id': 'cc' },
]
And, the ID list **List** as ['bb', 'aa']. By using the ID list, I want to return a new list ['Jane', 'John'] as **List _selectedList**.
I have tried to do it with the .**indexWhere**, however, I am stuck on the List where it has more than one value.
How can I return the List only with the name-value when there is more than one value to look for?
void main() {
var a = [
{ 'name': 'John', 'id': 'aa' },
{ 'name': 'Jane', 'id': 'bb' },
{ 'name': 'Lisa', 'id': 'cc' },
];
var b = ['bb', 'aa'];
var c = a.where((m) => b.contains(m['id'])).map((m) => m['name']);
print(c);
}
Result
(John, Jane)
Use a set to filter out the IDs efficiently.
var ids = ["aa", "cc"];
var idSet = Set<String>.from(ids);
var json = [
{ 'name': 'John', 'id': 'aa' },
{ 'name': 'Jane', 'id': 'bb' },
{ 'name': 'Lisa', 'id': 'cc' },
];
var _selectedList = json.where((data) => idSet.contains(data["id"]))
.map((data) => data["name"]).toList();
print(_selectedList);
Here, .where filters out the data where the ID matches one in the input list "IDs". Sets make the process efficient. Then, the resultant objects are passed to .map where the "name" field is extracted. Finally, the whole thing is converted into a list thus returning the list of names.
Output of the above code:
[John, Lisa]
Let's say I have a collection that looks like this:
{
'_id': ObjectId('abc'),
'customer': 'bob',
'products': {
'1234':
{'name': 'Shirt',
'productID': 5
},
'5679': {
'name': 'Hat',
'productID': 5
}
}
'1011': {
'name': 'Jeans',
'productID': 9
}
}
}
I am looking to remove all nested objects whose 'productID' property is 5, so the collection would look like this afterwards:
{'_id': ObjectId('abc'),
'name': 'bob',
'products': {
'1011': {
'name': 'Jeans',
'productID': 9
}
}
}
I know the following information:
customer: bob
productID: 5
Is it possible to do a wildcard on 'products'? Something like this (it does not work):
db.update({'customer':'bob'}, {'$unset': {'products.*': {'productID': 9}})
If you have a choice, refactor your data to make each item a list element, e.g.
{
'customer': 'bob',
'products': [
{'code': '1234',
'name': 'Shirt',
'productID': 5
},
{'code': '5679',
'name': 'Hat',
'productID': 5
},
{'code': '1011',
'name': 'Jeans',
'productID': 9
}
]
}
Then your update becomes a piece of cake:
db.mycollection.update_one({'customer': 'bob'}, {'$pull': {'products': {'productID': 5}}})
result:
{
"customer": "bob",
"products": [
{
"code": "1011",
"name": "Jeans",
"productID": 9
}
]
}
Persisting with poor choices of schema will no yield long term rewards.
I have a python request returning api data in json format like below:
[
{
'name': 'xyz',
'address': 'yyy'
},
{
'name': 'abc',
'address': 'ccc'
}
]
I want to load this data in MongoDB every day as such irrespective of if there have been any changes to address from the api json response output or not, along with a datetimestamp field added with every document insert/update for each name key in json object, like below:
[
{
'id' : objectid(123456),
'name': 'xyz',
'address': 'yyy'
'dttm' : '2020-08-26:01:20:30'
},
{
'id' : objectid(123457),
'name': 'abc',
'address': 'ccc'
'dttm' : '2020-08-26:01:20:30'
}
{
'id' : objectid(123458),
'name': 'xyz',
'address': 'zzzzzzzzzzzzzzzzzzz'
'dttm' : '2020-09-26:03:01:20'
},
{
'id' : objectid(123459),
'name': 'abc',
'address': 'ccc'
'dttm' : '2020-09-26:03:02:30'
}
]
In above example - name "xyz" has address change from previous run, but name "abc" had no change but still loading with a different datetimestamp
Sample code:
import requests
import json
from pymongo import MongoClient
url='xxx'
header={'Auth':'xyz', 'Content-Type': 'application/json'}
payload={}
api_data = requests.request("POST", url, data=json.dumps(payload), headers=header).json()
client = MongoClient('mongodb://localhost:27017')
db = client[test_db][test_collection]
db.update_one({api_data}, {$set:{dttm:datetime.today()}},{'upsert':True}) ##===>>what is the valid way to construct this using PyMongo ??
client.close()
You can provide the timestamp in the update document, it will be written into the database on both inserts and updates.
For upsert, see Fast or Bulk Upsert in pymongo.
I have this document:
[{
_id: "5a9eff23b9eea111a00016c8",
participants: [
2,
3
]
}]
I would like to know if it's possible to add and format fields on array result, something like this.
{
_id: "5a9eff23b9eea111a00016c8",
participants: [
{
_id: 2,
order: 22,
},
{
_id: 3,
order: 22,
}
]
}
This should not be saved in the database, it should be only attached on response.
If it's possible, I would like an advice.
#rollstuhlfahrer
Well , i don't think so , these fields ( order , _id) , doesn't exists in other table , they are custom
I've figured it out. Works well. Done in PHP.
I've used $map , see the documentation below.
https://docs.mongodb.com/manual/reference/operator/aggregation/map/
[
'$project' => [
'_id' => 0,
'title' => '$title',
'participants' => [
'$map' => [
'input' => '$participants',
'as' => 'part',
'in' => [
'recipient' => '$$part',
'status' => false,
]
]
]
]]
Here is the result:
{
title: "Channel#O4ScAPkYLz",
participants: [
{
recipient: 2,
status: false
},
{
recipient: 1,
status: false
}
]
}
I have MongoDB documents structured like this:
{_id: ObjectId("53d760721423030c7e14266f"),
fruit: 'apple',
vitamins: [
{
_id: 1,
name: 'B7',
usefulness: 'useful',
state: 'free',
}
{
_id: 2,
name: 'A1',
usefulness: 'useful',
state: 'free',
}
{
_id: 3,
name: 'A1',
usefulness: 'useful',
state: 'non_free',
}
]
}
{_id: ObjectId("53d760721423030c7e142670"),
fruit: 'grape',
vitamins: [
{
_id: 4,
name: 'B6',
usefulness: 'useful',
state: 'free',
}
{
_id: 5,
name: 'A1',
usefulness: 'useful',
state: 'non_free',
}
{
_id: 6,
name: 'Q5',
usefulness: 'non_useful',
state: 'non_free',
}
]
}
I want to query and get all the fruits which have both {name: 'A1', state: 'non_free'} and {name: 'B7', state: 'free'}.
In the worst case I want at least to count these entries if getting them is not possible and if the equivalent code exists for pymongo, to know how to write it.
For the given example I want to retrieve only the apple (first) document.
If I use $elemMatch it works only for one condition, but not for both. E.g. if I query find({'vitamins': {'$elemMatch': {'name': 'A1', 'state': 'non_free'}, '$elemMatch': {'name': 'B7', 'state': 'free'}}}) it will retrieve all the fruits with {'name': 'B7', 'state': 'free'}.
In this case you can use the $and-operator .
Try this query:
find({
$and: [
{'vitamins': {'$elemMatch': {'name': 'A1', 'state': 'non_free'} } },
{'vitamins': {'$elemMatch': {'name': 'B7', 'state': 'free'} } }
]
});
To explain why you received only the result matching the second criteria: The objects inside each {} you pass to MongoDB are key/value pairs. Each key can only exist once per object. When you try to assign a value to the same key twice, the second assignment will override the first. In your case you assigned two different values to the key $elemMatch in the same object, so the first one was ignored. The query which actually arrived in MongoDB was just find({'vitamins': {'$elemMatch': {'name': 'B7', 'state': 'free'}}}).
Whenever you need to apply the same operator to the same key twice, you need to use $or or $and.
var fruits = db.fruits.find({
"vitamins": {
$all: [{
$elemMatch: {
"name": "A1",
"state": "non_free"
}
}, {
$elemMatch: {
"name": "B7",
"state": "free"
}
}]
}
})
let query = [];
query.push({
id: product.id,
});
query.push({ date });
for (const slot of slots) {
query.push({
slots: {
$elemMatch: {
id: slot.id,
spots: { $gte: slot.spots },
},
},
});
}
const cal = await Product.findOne({ $and: query });