VBA Filter Error If criteria is not available - autofilter

Im using filter in vba with specific criteria, however im encountering error when the criteria is not available.
If criteria "First" is not available in the summary report, I want the vba to go to the next criteria, "Second". Copy the data and paste in "Second" Tab. So the "First" Tab is blank since criteria is not available in the summary report.
Below is my code...
Range("C1").AutoFilter Field:=3, Criteria1:="First"
Range("Table6").Select
Selection.SpecialCells(xlCellTypeVisible).Select
Application.CutCopyMode = False
Selection.Copy
Worksheets("First").Select
Range("A2").Select
Selection.PasteSpecial Paste:=xlPasteValuesAndNumberFormats, _
Operation:= xlNone, SkipBlanks:=False, Transpose:=False
Worksheets("ReportTemp").Select
Range("C1").AutoFilter Field:=3, Criteria1:= "Second"
Range("Table6").Select
Selection.SpecialCells(xlCellTypeVisible).Select
Application.CutCopyMode = False
Selection.Copy
Worksheets("Second").Select
Range("A2").Select
Selection.PasteSpecial Paste:=xlPasteValuesAndNumberFormats, _
Operation:= xlNone, SkipBlanks:=False,Transpose:=False`

Related

Algolia: Fetch records where both facet conditions are satisfied

An example data structure of my record(s) are:
{
foo: "bar",
foo1: [
{ b1: "x", b2: "y" }
]
}
I am using React InstantSearch widgets where I have many refinement lists, two of which are on foo1.b1 and foo.b2 attributes.
Expectation - user selects value "x" for foo1.b1 attribute and "y" for foo1.b2 attribute. Records that have both values set should be returned. (AND condition).
Actual: Records where either foo1.b1 is "x" OR foo1.b2 is "y" are being returned.
Since I am using React InstantSearch widget and RefinementList, I am not sure how I can achieve the above. I looked at connectRefinmentList and virtual refinement lists but they seem to only work with a single attribute at a time.
Here's a Demo link of the issue.
Select Language as English and Language Level as Conversational.
Expected: Only Item # 3 and Item # 4 to show up.
Actual: All 4 items are seen.

Pymongo Find & Update problems

Background
I'm making an application which takes an input through a Discord bot and then puts the input in a Google Document. During that process, I'm using Flask with Pymongo to find documents whose isNew property is set to true and send it back to Google Docs script. After that's done I want to set the isNew property of the documents to set to false. Alternatively, I can set the isNew to false before I send, since i can't call a function successfully, after I have returned the response in Flask.
Based on what I've experimented with, whenever I get new documents using a <CollectionName>.find() request, and tried to update the isNew property subsequently using a CollectionName.update_many() command, it results in the variable storing the original find command documents to go blank.
Code Attempts:
1. update many while trying to return new documents
import pymongo
# mongodb db connection string
connectionString = ('mongodb://localhost:27017')
client = pymongo.MongoClient(connectionString)
db = client['tempBotDB']
# 3 types of questions: quiz, cross, hunt
# separate collections for each type of strings
quizQs = db['quizQs']
crossQs = db['crossQs']
huntQs = db['huntQs']
# Properties of a question: isnew, type, question, answer
def saveQ(qObj): # Saves a question to the db
qType = qObj.get('type')
# creating own qObj
q = {
'question': qObj.get('question'),
'answer': qObj.get('answer'),
'isNew': bool(True)
}
if qType == 'quiz':
result = quizQs.insert_one(q)
elif qType == 'cross':
result = crossQs.insert_one(q)
elif qType == 'hunt':
result = huntQs.insert_one(q)
else:
result = ('Error: "type" of question can only be'
'one of : cross, hunt, quiz')
return result
def getQs(qType): # Gets all the questions by given type
if qType == 'quiz':
result = quizQs.update_many(
{'isNew': bool(True)},
{'$set': {'isNew': bool(False)}},
{returnOriginal: True}
)
print(result)
else:
result = ('Error: "type" of question can only be'
'one of : cross, hunt, quiz')
getQs('quiz')
Error: NameError: name 'returnOriginal' is not defined
Also tried with returnNewDocument instead of returnOriginal. But got: NameError: name 'returnNewDocument' is not defined
Using a find followed by an update within the same function
def getQs(qType): # Gets all the questions by given type
if qType == 'quiz':
selector = {'isNew': False}
modifier = {'$set': {'isNew': True}}
result = quizQs.find(selector)
#fakeRes = quizQs.update_many(selector, modifier)
print('res', result)
for i in result:
print('result', i)
#print('fakeres', fakeRes)
# for i in fakeRes:
# print('FakeRes', i)
else:
result = ('Error: "type" of question can only be'
'one of : cross, hunt, quiz')
If I uncomment the update command, the result of the find command becomes uniteratable (I get an error message), which to the best of my knowledge means that it's empty. Here's what happens:
def getQs(qType): # Gets all the questions by given type
if qType == 'quiz':
selector = {'isNew': False}
modifier = {'$set': {'isNew': True}}
result = quizQs.find(selector)
fakeRes = quizQs.update_many(selector, modifier)
print('res', result)
for i in result:
print('result', i)
print('fakeres', fakeRes)
for i in fakeRes:
print('FakeRes', i)
else:
result = ('Error: "type" of question can only be'
'one of : cross, hunt, quiz')
I get an the following output:
res <pymongo.cursor.Cursor object at 0x10e34ca50>
fakeres <pymongo.results.UpdateResult object at 0x10e35bfa0>
Traceback (most recent call last):
File "db.py", line 63, in <module>
getQs('quiz')
File "db.py", line 55, in getQs
for i in fakeRes:
TypeError: 'UpdateResult' object is not iterable
Notice how iterating through the result object did not print anything, pointing to the fact that it goes empty.
So, to conclude, my main question is:
How do I successfully find and update multiple documents in mongodb, while retrieving the update documents, OR just the found documents (not updated) [EITHER of them will work as i won't need to access the property I update]
Lastly, would it be logical to first do a find and then update_one on each document while generating a list of dictionaries of the updated documents and then finally returning that list to the user?
I'd really appreciate any help.
There's a few ways to do this, but you can't get the list of updated documents from an update_many - Mongo doesn't support that.
So your best approach is:
for record in db.mycollection.find({'isNew': False}):
result = db.mycollection.update_one({'_id': record['_id']}, {'$set': {'isNew': True}})
print(record)
# Add in logic here to assemble records for return to the user

MongoDB pagination

I'm trying to implement MongoDB pagination based on a query which always should short by a date field named updateTime.
I tried to implement pagination paging by a next and previous ObjectID using the operators $gt and $lt and limiting by some results page size.
In adition the query may include multiple filters (distinc field matching values).
In order to build a consistent pagination approach, based on the query which may include or not filters, I try to determine the first and last ObjectID despite of the numbers of pages a search might generate.
#staticmethod
def paginate_reviews(gt_oid, lt_oid, account, location, rating, responded, start_datetime=None, end_datetime=None):
query = {'location': {'$in': location}}
if account is not None:
query['account'] = account
if start_datetime is not None and end_datetime is not None:
query['updateTime'] = {'$gte': start_datetime, '$lte': end_datetime}
if gt_oid is not None:
query['_id'] = {'$gt': ObjectId(gt_oid)}
elif lt_oid is not None:
query['_id'] = {'$lt': ObjectId(lt_oid)}
if rating is not None and len(rating) is not 0:
rating = [int(r) for r in rating]
query['starRatingNumber'] = {'$in': rating}
if responded is not None:
responded = json.loads(responded)
query['reviewReply'] = {'$exists': responded}
reviews = Review.objects.filter(__raw__=query).order_by('-updateTime', '_id')[:25]
response = {
'reviews': reviews
}
if gt_oid is None and lt_oid is None:
first = Review.objects().filter(__raw__=query).order_by('updateTime').first()
last = Review.objects().filter(__raw__=query).order_by('-updateTime').first()
first_oid = str(first.to_mongo().get('_id')) if first is not None else None
last_oid = str(last.to_mongo().get('_id')) if last is not None else None
response['first_oid'] = first_oid
response['last_oid'] = last_oid
return response
Where first_oid is supposed to be the first document of first page and last_oid should be the last element of last page.
When I'm at first page, I query a next one like this:
db.review.find({"_id" : {$gt: ObjectId("5a776c41c68932281c2240f1")}}).sort({'_id': 1, 'updateTime': -1}).limit(25)
Being 5a776c41c68932281c2240f1 the last element of first page.
So far, it's working properly when trying to paginate forward. However when trying to paginate backwards something weird happens as even I'm in a 3rd, 5th or whatever page, a match using $lt passing the first element in a page is returning first element of page 1.
This is breaking my whole implementation. How should I adjust it?

Mongoid embedded document returning empty for queries

When I query the embedded model, no records are returned despite there being plenty of parent records containing instances of the embedded model.
There are two models, a Label embedded in a Band:
class Band
include Mongoid::Document
embeds_one :label
end
class Label
include Mongoid::Document
field :name, type: String
embedded_in :band
end
I can query Band (Band.all, Band.find etc) just fine, but when I query Label, it returns nothing. For instance:
I create the band with the embedded label, and save it:
> b = Band.create
=> #<Band _id: 516cff525543d8842e000008, _type: nil>
> b.build_label name: "new label"
=> #<Label _id: 516cff5a5543d8842e000009, _type: nil, name: "new label">
> b.save
=> true
Then I query the Band model, and all is fine:
> Band.all.to_a
=> [#<Band _id: 516cff525543d8842e000008, _type: nil>]
> Band.count
=> 1
> Band.first.label
=> #<Label _id: 516cff5a5543d8842e000009, _type: nil, name: "new label">
> Band.find "516cff525543d8842e000008"
=> #<Band _id: 516cff525543d8842e000008, _type: nil>
But when I query the Label model, nothing shows up!
> Label.all.to_a
=> []
> Label.count
=> 0
> Label.last
=> nil
> Label.first
=> nil
> Label.find "516cff5a5543d8842e000009" # this is the label id from Band
=> nil
I'm almost positive this is not intended behavior. The code is directly from an example on the Mongoid docs here: http://mongoid.org/en/mongoid/docs/relations.html#embeds_one
What am I missing?
In mongo your queries always target collections, i.e. full documents that may embed other documents. For mongo it's just one big JSON/BSON document. Now, Label.all or Label.all are equivalent to querying the Label collection. Since labels are not stored in the Label collection, those queries return nothing. However, you can still query labels on the Band collection by calling
Band.where(:'labels._id' => "516cff5a5543d8842e000009")
or something like
Band.where(:'labels.name' => "rock")
This is fine if you want to get all bands with a certain label. Getting all labels this way, however, is very expensive and not recommended. What's your main use case? If it is showing labels for a band or getting bands with a certain label, then embedding is great. Otherwise, you could use relations (has_many/belongs_to), or denormalize completely, i.e. save labels within bands and in a separate collection at the same time (leading to redundant data).
I think you should use has_many, has_one, belongs_to methods for making possible to run queries as you want like Label.count.
When you embed document into another document it will become as a part(serialized property) of a document. If you want to select labels you should find Band at first and then check the label property. It should definitely work.

Mongodb findAndModify embedded document - how do you know which one you've modified?

findAndModify in mongodb is great, but I am having a little trouble knowing which embedded document I modified.
Here is an example where a Post embeds_many Comments. (I'm using Mongoid ORM but the question is generic to any MongoDB setup).
begin
p = Post.asc(id).where(comments: { '$elemMatch' => {reserved: false} }).find_and_modify({'$set' => {'comments.$.reserved' => true}}, {new: true}
# now i need to find which comment I just reserved
c = p.comments.select{|c| c.reserved }.first
...
ensure
c.update_attribute :reserved, false
end
Ok this sort of works, but if I have multiple processes running this simultaneously my select could choose a comment that another process had reserved (race condition).
This is the closest I have for now (reserving by process id):
begin
p = Post.asc(id).where(comments: { '$elemMatch' => {reserved: nil} }).find_and_modify({'$set' => {'comments.$.reserved' => Process.pid}}, {new: true}
# now i need to find which comment I just reserved
c = p.comments.select{|c| c.reserved == Process.pid }.first
...
ensure
c.update_attribute :reserved, nil
end
Which seems to work. Is this the best way to do this or is there a better pattern?
Was able to solve it by generating a SecureRandom.hex and setting this on the embedded document with find_and_modify. Then you can loop through the embedded documents and see which one has your matching hex, to see which one you are working with.